第一题 Leetcode 395

Loading...​leetcode.com

Find the length of the longest substring T of a given string (consists of lowercase letters only) such that every character in T appears no less than k times.

Example 1:

Input:
s = "aaabb", k = 3Output:
3The longest substring is "aaa", as 'a' is repeated 3 times.

暴力解法应该是

,尝试所有的substring的组合,对于每个substring,check还需要
.如果调整好访问顺序,带一些memorization,可以轻松把check的时间降到
,从而让总时间复杂度降到
.

讨论区有这样一种解法,把复杂度降到了

.

Loading...​leetcode.com

思路是这样的。对于整个string来说,如果有字母的出现次数小于K,那么这个字母不可能被包含在答案里面。于是我们可以用这些不达标的字母作为分割,把整个string分割成若干截,每一截都有可能包含正确答案,但是不一定。

为什么说有可能呢,因为本来符合出现次数要求的字母,可能被分割到了不止一段小截中,每一截中出现的次数又不够K了。比如aba, K=2这个例子,b一开始出现的次数不足2,所以用来做分割,我们只考虑a和a(左右两个子字符串)。但是这时候每一个小截中包含的a的个数也不足2了。

所以对于分割开来的每一个小截,我们都可以当成一个新的问题,然后递归来处理。代码实现如下:

int longestSubstring(string s, int k) {return longestSubstring_recur(s, k, 0, s.size());
}int longestSubstring_recur(const string& s, int k, int first, int last) {int count[26] = {0};for (int j = first; j < last; ++j) ++count[s[j] - 'a'];int max_len = 0;for (int j = first; j < last;) {while (j < last && count[s[j]-'a']<k) ++j;if (j == last) break;int l = j;while (l < last && count[s[l]-'a']>=k) ++l;//all chars appear more than k timesif (j == first && l == last) return last-first; max_len = max(max_len, longestSubstring_recur(s, k, j, l));j = l;}return max_len;
}

有意思的部分来了。作者说复杂度是O(N)因为递归的层数最多是26层。这个结论乍一看有点懵,于是我又看了看底下的讨论,发现是这样的。我们已经看到每一次递归,我们都会把不符合要求(出现次数小于K)的字母给去掉,因此最多只有26个字母可以去,一个字母没有机会被去除两次。(比如在某一次递归中字母a出现的次数小于K,那么它在recursion tree中的所有children中都不会出现字母a了。)每一层递归所做的工作的总和又是线性的,所以总体的实现复杂度也是线性的。

第二题 Leetcode 749

Loading...​leetcode.com

A virus is spreading rapidly, and your task is to quarantine the infected area by installing walls.

The world is modeled as a 2-D array of cells, where 0 represents uninfected cells, and 1 represents cells contaminated with the virus. A wall (and only one wall) can be installed between any two 4-directionally adjacent cells, on the shared boundary.

Every night, the virus spreads to all neighboring cells in all four directions unless blocked by a wall. Resources are limited. Each day, you can install walls around only one region -- the affected area (continuous block of infected cells) that threatens the most uninfected cells the following night. There will never be a tie.

Can you save the day? If so, what is the number of walls required? If not, and the world becomes fully infected, return the number of walls used.

Example 1:

Input: grid =
[[0,1,0,0,0,0,0,1],[0,1,0,0,0,0,0,1],[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0]]
Output: 10
Explanation:
There are 2 contaminated regions.
On the first day, add 5 walls to quarantine the viral region on the left. The board after the virus spreads is:[[0,1,0,0,0,0,1,1],[0,1,0,0,0,0,1,1],[0,0,0,0,0,0,1,1],[0,0,0,0,0,0,0,1]]On the second day, add 5 walls to quarantine the viral region on the right. The virus is fully contained.

直接放官网的solution:

Approach #1: Simulation [Accepted]

Intuition

Let's work on simulating one turn of the process. We can repeat this as necessary while there are still infected regions.

Algorithm

Though the implementation is long, the algorithm is straightforward. We perform the following steps:

  • Find all viral regions (connected components), additionally for each region keeping track of the frontier (neighboring uncontaminated cells), and the perimeter of the region.
  • Disinfect the most viral region, adding it's perimeter to the answer.
  • Spread the virus in the remaining regions outward by 1 square.
class Solution {Set<Integer> seen;List<Set<Integer>> regions;List<Set<Integer>> frontiers;List<Integer> perimeters;int[][] grid;int R, C;int[] dr = new int[]{-1, 1, 0, 0};int[] dc = new int[]{0, 0, -1, 1};public int containVirus(int[][] grid) {this.grid = grid;R = grid.length;C = grid[0].length;int ans = 0;while (true) {seen = new HashSet();regions = new ArrayList();frontiers = new ArrayList();perimeters = new ArrayList();for (int r = 0; r < R; ++r) {for (int c = 0; c < C; ++c) {if (grid[r][c] == 1 && !seen.contains(r*C + c)) {regions.add(new HashSet());frontiers.add(new HashSet());perimeters.add(0);dfs(r, c);}}}if (regions.isEmpty()) break;int triageIndex = 0;for (int i = 0; i < frontiers.size(); ++i) {if (frontiers.get(triageIndex).size() < frontiers.get(i).size())triageIndex = i;}ans += perimeters.get(triageIndex);for (int i = 0; i < regions.size(); ++i) {if (i == triageIndex) {for (int code: regions.get(i))grid[code / C][code % C] = -1;} else {for (int code: regions.get(i)) {int r = code / C, c = code % C;for (int k = 0; k < 4; ++k) {int nr = r + dr[k], nc = c + dc[k];if (nr >= 0 && nr < R && nc >= 0 && nc < C && grid[nr][nc] == 0)grid[nr][nc] = 1;}}}}}return ans;}public void dfs(int r, int c) {if (!seen.contains(r*C + c)) {seen.add(r*C + c);int N = regions.size()regions.get(N - 1).add(r*C + c);for (int k = 0; k < 4; ++k) {int nr = r + dr[k], nc = c + dc[k];if (nr >= 0 && nr < R && nc >= 0 && nc < C) {if (grid[nr][nc] == 1) {dfs(nr, nc);} else if (grid[nr][nc] == 0){frontiers.get(N - 1).add(nr*C + nc);perimeters.set(N - 1, perimeters.get(N - 1) + 1);}}}}}
}

讲解还是比较清楚的,就是一般的simulation步骤。我一开始想keep track of所有的受感染的region,然后每次更新受感染的region,而不是遍历整个board。后来发现并不可行,因为在更新的过程中,多个受感染的region有可能会融合成一个新的更大的region,这一部分很难追踪。

比较有意思的是答案里的时间复杂度:

Time Complexity:

whereR, C

R,Cis the number of rows and columns. After timett, viral regions that are alive must have size at least

, so the total number removed across all time is
.
, R是行数,C是列数,简而言之
就是整个board的面积。但是4/3 又是怎么出来的呢。

首先我们知道,每一次iteration中,我们都要遍历整个board,因此每个iteration都是

的时间复杂度。下面的问题是在最差的情况下,会有多少次iteration。

假设我们没有进行任何的quarantine,每一个受感染的区域面积随时间t的变化为

.因为这是一个2D的平面,所以面积增长随时间是平方的关系,如果是3D的空间,则是立方的关系。在这种情况下:在t时,最大的受感染的区域的面积至少为
。我们还知道,在(t-1)时,最大的受感染的区域的面积为
.但是因为在t-1是被隔离了,因此那块区域就不能继续增长了。这就是
的来历。虽然我觉得这个还可以继续扩展,到
.

因此总感染面积随时间t的变化为立方关系(最高次幂为3).当总感染面积达到了整个board的大小的时候,也就是iteration停止的时间。

。 因此遍历的次数为
。 考虑到每次遍历的工作量为
,相乘得到总的时间复杂度为
.

在给 @Chao Xu review了我的思路之后,他指出平方增长并不严谨。然后给了我这一样一个图。

图中阴影和纯黑都为病毒。阴影的是一个非常大的像梳子状的病毒区域。第一次时间一定会把阴影部分的区域给隔离起来(因为是是危害最大的)。从此之后,纯黑部分的病毒区域增长为线性,也就是需要

次iteration才能完全隔离或感染。当
,其时间复杂度
.最终的复杂度应当为
.

dfs时间复杂度_两道有意思的时间复杂度计算相关推荐

  1. python index函数时间复杂度_初学python之以时间复杂度去理解列表常见使用方法

    列表list,一个有序的队列 列表内的个体为元素,由若干个元素按照顺序进行排列,列表是可变化的,也就是说可以增删 list定义 常用的列表定义方式: 使用[] 或者 a = list() 取数列表可以 ...

  2. python二分查找时间复杂度_二分查找算法的时间复杂度计算(logN)

    二分查找算法的时间复杂度计算(logN) 马富天 2019-08-10 20:25:24 54 [摘要]二分查找算法是对顺序查找算法的优化,二分查找算法的前提是数列是一个有序数列,递增或者递减,本文就 ...

  3. 求杨辉三角的前n行数据_两道简单的套公式算法题:杨辉三角

    杨辉三角应该是大家很早就接触到的一个数学知识,它有很多有趣的性质: 每个数字等于上一行的左右两个数字之和,即 C(n+1,i) = C(n,i) + C(n,i-1) 每行数字左右对称,由 1 开始逐 ...

  4. Java多道程序坐标图_两道java基础题,每天赶任务,多忘了怎么写这种代码。

    题目: 输入一整数,找出大于该整数的最小完美数,找到返回该数,找不到返回0. 完美数:一个数如果恰好除与各位书的和余22,这个数就成为"完美数". 审题 再看一遍,整数应该包括负数 ...

  5. dfs时间复杂度_一文吃透时间复杂度和空间复杂度

    学习数据结构和算法的第一步(公众号:IT猿圈) 时间复杂度 最常见的时间复杂度有哪几种 「O(1)」:Constant Complexity 常数复杂度 「O(log n)」:Logarithmic ...

  6. 冒泡和快速排序的时间复杂度_八大排序算法性能分析及总结

    一.排序算法说明 排序的定义:对一个无序的序列进行排序的过程. 输入:n个数:a1,a2,a3,-,an. 输出:n个数的排列:a1,a2,a3,-,an,使得a1<=a2<=a3< ...

  7. b+树时间复杂度_前端大神用的学习笔记:线段树和树状数组

    全文篇幅较长,细心理解一定会有收获的♪(^∇^*). 1|0线段树 1|1一些概念     线段树是一种二叉搜索树,每一个结点都是一个区间(也可以叫作线段,可以有单点的叶子结点),有一张比较形象的图如 ...

  8. 【数据结构】时间复杂度_空间复杂度

    作者:旧梦拾遗186 专栏:数据结构成长日记 每日励志: 如果有一天,你的努力配得上你的梦想,那么你的梦想也绝对不会辜负你的努力. 前言: 小编带大家来学习数据结构中的复杂度问题. 目录 1.算法效率 ...

  9. 【计算理论】计算复杂性 ( 两个带子的图灵机的时间复杂度 | 证明多个带子图灵机时间复杂度 )

    文章目录 一.确定性模型的计算复杂性关系 二.证明 "多个带子图灵机时间复杂度是 O(n2)\rm O(n^2)O(n2)" 一.确定性模型的计算复杂性关系 计算的 复杂性 取决于 ...

最新文章

  1. 前后端分离的探索(一)
  2. 退一步 - 王阳明的心学智慧
  3. 2011年春季 软件项目管理 实验安排
  4. 面向对象封装继承多态五大基本原则魔法方法反射
  5. 牛客小白月赛12 D 月月给华华出题 (欧拉函数,数论,线筛)
  6. ulink php,【转载】15款USB数字界面横向评测(对比顶级CD转盘)!多看点!
  7. ajax 分页 评论刷新,评论:js无刷新分页(原创)
  8. Python isalpha()方法
  9. 转:html id与name区别
  10. Servlet异步处理性能优化的过程
  11. spring基于注解的 IOC 配置ioc实现crud
  12. CCF - 201604-2 - 俄罗斯方块
  13. BZOJ2259[Oibh] 新型计算机
  14. echar3D地图+3D柱形图
  15. 君康人寿2019年排名_2019中国保险公司竞争力报告出炉 君康人寿盈利能力排名第二...
  16. GitHub又放大招,Python版本的植物大战僵尸还能作弊玩!
  17. 中国茶道的基本精神(转)
  18. 判断闰年和平年的程序
  19. idea 控制台搜索快捷键
  20. C++在使用fgetc读取文件时出现方框乱码

热门文章

  1. 移动设备 计算机设备,移动设备
  2. java便签小程序原码_localStorage实现便签小程序
  3. Stream将List转换为Map
  4. Java 语言 ArrayList 和 JSONArray 相互转换
  5. Ubuntu下华为方舟编译器环境安装
  6. JAVA中Calendar与Date类型互转
  7. 唯一索引和逻辑删除冲突
  8. Tomcat与JDK版本对应关系
  9. Linux后台运行jar不产生nohup.out
  10. ORACLE 归档日志打开与关闭