楼主: Wilson_2014
跳转到指定楼层
上一主题 下一主题
收起左侧

蜗居匹兹堡孤独刷题中

🔗
 楼主| Wilson_2014 2019-2-13 11:54:47 | 只看该作者
全局:
Day 8 - 2019/02/12

今天耗在685太长时间,有点后悔

684. Redundant Connection
这个题的关键在于:When we count an edge in, if two nodes have already been in the same connected component, the edge will result in a cycle. That is, the edge is redundant.
这道题跟环没关系,而跟connected component有关,所以一开始我的思考方向错了。
还有我一开始很困惑的一点是,对于Input: [[1,2], [1,3], [2,3]]的时候, [1, 2]这条边也可以是答案啊?仔细读题就会发现有条件限制了这个边不能成为答案

很显然这个题是关于connected component的,很自然会想到UnionFind解法。并和查算O(1)总体就是O(n)

DFS的方法也练了一下,在构建图的过程中,每加入一条边,都先DFS一遍是否能够找到这条边的两个点,如果能够找到,说明这条边就是答案。
这道题的DfS非常简单,没有回溯的代码。
dfs方法是O(n^2),因为dfs on a tree is O(n),这道题里E = V

685. Redundant Connection II
这道题难啊。耗了一天!

如何能够确定自己已经穷举了所有情况?下面的case对于我来说非常难想到:
[[2,1],[3,1],[4,2],[1,4]]
在这种情况下,既出现了环,又出现了双亲,这时候那个造成双亲的edge不是答案,而需要返回[2, 1]这条边(也就是造成双亲情况的先出现的那条边)。

这个题这道题所涵盖的这种树图结构的种种情况应该具有某种一般性的意义,只是以我目前的认知水平,还不能够了解。

但是这道题我学到了在Tree中对Union Find的灵活运用,这时候我们只需要知道维护每个点的root信息就可以了。
掌握测出以下两种情况的技术估计也比较有用:
1)找到造成某点有两个parent的那条后出现的边 (parent[y] != parent[x] && y不是新加的点)
2)造成环的那条边 (如果一直是parent[x] == parent[y],那么最后一条边必定成环)
并查集解法的时间复杂度大概是O(n)

959. Regions Cut By Slashes
这道题第一个难点在于想到怎么把一个字符转换成四个node,这样grid就变成了n * n * 4这么大。 这样这道题就变成了number of islands的变形了。
优化的解法就是在维数组中运用unionfind。
另一个难点是要搞清楚什么时候union,仔细分析理解这三种字符的特点。
这个正方形边长为n,所以时间复杂度是O(n^2)

305. Number of Islands II
这是应该练的一道并查集的题。
并查集的时间复杂度说起来比较复杂。就说最终是O(1)吧。这里有L此操作,也就是O(L)了

今天的题都是用并查集做的,记得得用DFS练一遍。

评分

参与人数 1大米 +1 收起 理由
Wu_kong + 1 赞一个

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-14 11:48:29 | 只看该作者
全局:
本帖最后由 Wilson_2014 于 2019-2-14 11:54 编辑

Day 9 - 2019/02/13

为啥不是没信儿就是据信,一阵一阵的负面情绪,没法保持乐观安心刷题。听说大公司每年的hc都是3月才放出来,是这么回事吗?

314. Binary Tree Vertical Order Traversal
热心地友告诉我有这么道题,确实和当时面试的很像。做了一下。但是就是想不明白怎么可能用前序遍历嘛

947. Most Stones Removed with Same Row or Column

HashMap for UnionFind:
对于UnionFind,parent数组大小不确定的时候,用Map比较好。

Unify Index for UnionFind: Union(row, col);
lee215大神用到了Unify index,对于col index使用Unary bitwise complement operator [~]
Three-bit signed integers
DecimalValue        Binary (two's-complement representation)
0                                000        
1                                001        
2                                010        
3                                011        
-4                                100        
-3                                101        
-2                                110        
-1                                111        

或者就直接add 10000 to col index. So we use 0 ~ 9999 for row index and 10000 ~ 19999 for col.
不然的话,硬套number of islands是不容易的。

这道题的UnionFind没有用rank,所以时间复杂度是O(logN).总体是O(NlogN).

DFS解法值得一练:
首先是graph的表示方法,可以用两个Map:rMap和cMap
然后用Set<String>表示visited, key = r + " " + c

DFS的时间复杂度是O(N^2)?我对DFS时间复杂度心里还是没有数啊。下一个标签该做DFS了。

Number Of Islands相关的DFS都得练一遍

发现自己DFS的基本功不行,开始练DFS标签吧。

78. Subsets这道题是DFS回溯法的最基本练习题。可以画一下搜索树来观察回溯的过程。DFS算法通常考虑的问题有以下四点:
1.如何定义这DFS函数
2.这个递归的出口在哪里
3.递归的拆解
4.如何保证不走回头路
对于这道题而言:
1)DFS函数的定义就是将以List开口的所有subsets加入到result中。
2)我们用index来规定搜索的顺序,所以当index等于nums.length的时候,就是结束的时候。
4)按index顺序进行搜索,保证了不走回头路。

搜索类问题时间复杂度的通用公式是:答案个数 × 构造答案的时间
对于这道题而言:O(n * 2^n)

这道题还有一个bit manipulation的解法,以后放到一起总结吧。还有就是位运算的时间复杂度也是一样的。

90. Subsets II (nums contains duplicates)
这道题的关键在于:对于duplicates的number,我们规定必须从第一个数开始连续取(只关心去了多少个,不关心去了哪几个)
if ( i != start && nums == nums[i - 1]) continue; //这说明我们回溯到了一个duplicate,这个数不是duplicates中的第一个。

320. Generalized Abbreviation看起来和subsets有点像,但这个backtrack要复杂多了。递归的定义和拆解都有所不同。
In our problem, the partial candidates are incomplete abbreviations that can be extended by one of the two choices:
        1. keep the next character;
        2. abbreviate the next character.
还有就是记住不管在什么时候改变了里面的StringBuilder,都要记住变回原样sb.setLength(originalLen); 这样空间复杂度是O(L)
这道题倒是不如直接用String curr,这样减少了不少回溯操作。空间复杂度会增加到?O(L * 2^L)
时间复杂度和subset一样。O(L * 2^L)

这道题也还有位运算的解法,以后总结。


784. Letter Case Permutation
还是用回溯做的。
Binary Mask的位运算以后研究吧

39. Combination Sum
一个元素可以用重复多次的情况
技术:因为每次start pos都不变,所以必须sort然后比较candidates和target的大小来终结递归。

40. Combination Sum II
candidates里有重复,每个元素只能用一次
技术:candidates里有重复一般都要先sort,然后规定从第一个重复数开始取,不回溯其他重复数。

216. Combination Sum III
candidates里无重复,每个元素只能用一次

77. Combinations
candidates里无重复,每个元素只能用一次
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-15 10:43:20 | 只看该作者
全局:
Day 10 - 2019/02/14

今天堕落了,只做了一道题,情绪太低落。

评分

参与人数 2大米 +2 收起 理由
arcovitcher + 1 赞一个
Wu_kong + 1 赞一个

查看全部评分

回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-16 11:29:12 | 只看该作者
全局:
Day 11 - 2019/02/15

状态还是没有回来,就练了两道排列有关的题

做排列题目的时候,递归都不需要传入startIndex,画一画搜索树,好好体会一下这一点。这是排列问题和组合问题的关键不同。

46. Permutations
candidates里无重复,每个元素只能用一次。
        1. 递归的定义,找到以当前排列为首的所有排列。
        2. 递归的出口,排列数达到nums.length
        3. 在nums里找没有取过的元素
        4. 用set记录当前排列已经取过的元素。

47. Permutations II
candidates里有重复,每个元素只能用一次。
这时候主要是要提出rst里面的duplicate排列,因为虽然取的元素不同,但是元素的值是相同的,排列还是同一个排列
处理方法是,规定只能从duplicate中的第一个开始取,不能越过第一个,先取第二个。
if (i > 0 && nums[i] == nums[i - 1] && !visited.contains(i - 1)) continue;

60. Permutation Sequence
这道题可以加深对于排列数的理解。index上比较容易出错。一定要写出具体例子,推导出公式,再写代码。

267. Palindrome Permutation II完全套用47的方法会非常慢。用到了 StringBuilder.deleteCharAt()
这个题的时间复杂度是:答案个数是n!, 构造答案的时间是n,所以是O(n * n!)。与排列有关的搜索的时间复杂度通常都是阶乘级别的。
Recursion Tree达到的高度是O(n), 所以空间复杂度是O(n)
优化一:前检查这个string能不能排列成palindrome,做了这个改进之后至少能ac了。
优化二:把n变为 n / 2

答案中提到了一种permutation的技术:是通过字符交换产生新的排列。不清楚这技术对其他题有什么帮助,暂时不掌握吧。
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-17 09:37:17 | 只看该作者
全局:
Day 12 - 2019/02/16

锻炼身体和刷题一样重要,现在就健身去

51. N-Queens
一遍AC,开门红,加油!

这道题是一道排列题,所以不需要传入startPos。难点在于如何抽象成数学问题,以及一个判定攻击的小技巧。

答案的个数是n!级别,构造每个答案的时间是n,所以感觉应该是O(n* n!)

52. N-Queens II
和1的方法一样的。 还有一个bitmask的方法,这些位运算解法放到以后一起研究。

127. Word Ladder
简单图的最短路径一般用BFS,别忘了用Set保证不走回头路。

一个词通过一次变化可以变成dict中的哪些词,通过这道题要掌握的技术:
replace一个word的每一位,得到一个新词,这样的时间复杂度快于直接与字典中的词比较。

因为字典中词的个数可能很多,而单词的平均长度并不长,可能只有5,就算是10,O(25*L^2)约等于2500 优于 0(nL)约等于 10k × 10

BFS takes O(V + 2E) = O(V^2)
所以总体的时间复杂度是O(n^2). 如果我不建图,而是在BFS中找nextWords,那就是O(n^2 * L^2)

还有一点是,这道题我没有必要把图建立起来,其实只用找到nextWords就行了,下次练得时候注意点。

126. Word Ladder II
简单图最短路径是BFS,求所有路径是DFS,这道题求所有最短路径,所以就应该是BFS + DFS
对于DFS找所有方案的题目,一般时间复杂度都会非常高,如果能够知道下一步走的方向,就会大大降低时间复杂度。
先用BFS求出到终点的距离,然后沿着距离减小的方向走,这样就会减少递归的次数,并且保证不走回头路。

有个容易出错的地方:
for (String next : getNextWords(curr, dict)) {
    graph.get(curr).add(next);  //注意buildGraph和distanceMap是两个过程,写到continue下面就会丢解
    if (distanceMap.containsKey(next)) continue;
    distanceMap.put(next, distance);  
    q.offer(next);
}

139. Word Break
这道题先不用DP,体会一下用DFS的感觉,想一想如何定义递归,哪里进行了重复计算,想想recursion tree是什么样的,为什么时间复杂度是O(n^n),然后就知道如何用memorization优化了。优化后recursion tree的高度是n.
对于记忆化搜索或者动归类题目的时间复杂度:
通用公式是 O(状态总数 × 计算每个状态的时间) 这道题就是 O(n * n)

这道题有一个初始化boolean数组的小技巧:Boolean[] mem = new Boolean[len];

BFS 和 DP的解法留到以后做

140. Word Break II
记忆化搜索的题目,想想记忆什么比较好,递归怎么样定义比较好。
时间复杂度:计算每个状态需要O(n^2),一共要记录n个状态。
空间复杂度是O(n^3)

695. Max Area of Island
二维矩阵内的DFS我习惯的写法不好,要学习答案的写法。
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-18 10:40:22 | 只看该作者
全局:
本帖最后由 Wilson_2014 于 2019-2-18 23:38 编辑

Day 13 - 2019/02/17

今天虽然只做了两道题,只要感觉有收获就好吧

301. Remove Invalid Parentheses

最高票的那个解法,我只想用精妙绝伦来形容,花了不少时间才改写成功,使自己对这个逻辑相对清楚了一些.
但是还有一点不明白,就是这个代码是怎么保证对str做最小改变的? How this algorithm avoid exhaust all possible valid substrings, but only shortest ones.
现在想明白了,因为这个算法之处理多出来的右括号,不管什么时候发现这个右括号,都能判断它需要被去掉,所以能保证只去掉必要的括号。  

方法一:回溯法:
        1. 不需要stack判断括号valid,只需要计算左括号和后括号的数量。
        2. 只处理右括号,只要右括号数量超过左括号数量,就说明直到当前位置的string需要处理
        3. 在处理过程中,我们规定只去掉第一个右括号,这样就可以避免重复解,所以我们要传入上一次去掉右括号的位置
        4. 通过for循环,回溯处理当前位置之前的字符串,在不同位置删除右括号,会产生不同的解
        5. 递归的定义:startPos之前的字符串是valid,上一次删除括号的位置是lastRemoved。
        6. 递归的分解:for循环找可以删除的右括号,分别将他们删除并向下递归
        7. 递归的出口:当开始位置到达最右边。
        8. 递归的除重:规定只从第一个右括号开始删除,这样可以避免递归过程中产生重复解。
        9. 右括号处理完毕之后,将字符串反转,以同样方法处理左括号,处理完左括号之后,将这个解加入rst。
class Solution {
    public List<String> removeInvalidParentheses(String s) {
        List<String> rst = new ArrayList<>();
        remove(s, 0, 0, new char[]{'(',')'}, rst);
        return rst;
    }

    private void remove(String s, int startPos, int lastRemoved, char[] par, List<String> rst){
        int currInvalidPos = findInvalidPos(s, startPos, par);

        if(currInvalidPos == s.length()){
            String reversed = new StringBuilder(s).reverse().toString();
            if(par[0] == '('){
                remove(reversed, 0, 0, new char[]{')','('}, rst);
            }else{
                rst.add(reversed);
            }
            return;
        }
        
        for(int j = lastRemoved; j <= currInvalidPos; j++){
            if(s.charAt(j) == par[1] && (j == lastRemoved || s.charAt(j - 1) != par[1])){
                remove(s.substring(0, j) + s.substring(j + 1, s.length()), currInvalidPos, j, par, rst);
                //because we removed one character, currInvalidPos += 1, it will be the next startPos
            }
        }
    }
   
    private int findInvalidPos(String s, int startPos, char[] par) {
        int stack = 0;
        int i = startPos;
        while(i < s.length()){
            if(s.charAt(i) == par[0]) stack++;
            if(s.charAt(i) == par[1]) stack--;
            if(stack < 0) return i;
            i++;   
        }
        return s.length();
    }
}

方法二:回溯法:
相比之下,我更喜欢这个方法,思路上要清晰的多。
使用两个参数(maxOpenRm和maxCloseRm)保证 Remove the minimum number of invalid parentheses
联用unMatched保证curr是valid。这三个参数是非常好的设计。
然后就是结果要注意除重。
时间复杂度如果按搜索类问题来讲就是:答案个数 * 构造每个答案的时间
最坏情况我觉着是O(n * 2^n),但是这个算法里有pruning,所以时间复杂度应该远小于这个。

class Solution {
    public List<String> removeInvalidParentheses(String s) {
        int maxOpenRm = 0;
        int maxCloseRm = 0;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                maxOpenRm++;
            } else if (s.charAt(i) == ')'){
                if (maxOpenRm > 0) {
                    maxOpenRm--;
                } else {
                    maxCloseRm++;
                }
            }
        }
        Set<String> rstSet = new HashSet<>();
        dfs(s, 0, new StringBuilder(), rstSet, maxOpenRm, maxCloseRm, 0);
        return new ArrayList<>(rstSet);   
    }
   
    private void dfs (String s, int pos, StringBuilder curr, Set<String> rstSet, int maxOpenRm, int rmR, int unMatched) {
        //Limit max removal rmL and rmR for backtracking boundary.
        //Otherwise it will exhaust all possible valid substrings, not shortest ones.
        if (maxOpenRm < 0 || maxCloseRm < 0 || unMatched < 0) return;
        
        if (pos == s.length()) {
            //Check whether curr is valid
            if (maxOpenRm == 0 && maxCloseRm == 0 && unMatched == 0) {
                rstSet.add(curr.toString());
            }
            return;
        }
        
        int originalLen = curr.length();
        char c = s.charAt(pos);
        if (c == '(') {
            dfs(s, pos + 1, curr, rstSet, maxOpenRm - 1, maxCloseRm, unMatched);            //not adding this '(' to curr
            dfs(s, pos + 1, curr.append(c), rstSet, maxOpenRm, maxCloseRm, unMatched + 1);  // add to curr
        } else if (c == ')') {
            dfs(s, pos + 1, curr, rstSet, maxOpenRm, maxCloseRm - 1, unMatched);             // not adding this ')' to curr
            dfs(s, pos + 1, curr.append(c), rstSet, maxOpenRm, maxCloseRm, unMatched - 1);   // add to curr
        } else {
            dfs(s, pos + 1, curr.append(c), rstSet, maxOpenRm, maxCloseRm, unMatched);
        }
        curr.setLength(originalLen);
    }
}

方法三:BFS:
把每个str都当成一种状态,对于valid的str,加入rst,invalid的str,就改变其中的一个字符,然后加入Queue。
每个字符取和不取,一共有O(2^n)个subset,检查valid要O(n),一共是O(n*2^n)class Solution {
    public List<String> removeInvalidParentheses(String s) {
        List<String> rst = new ArrayList<>();
        if (s == null) return rst;
        Queue<String> q = new LinkedList<>();
        Set<String> visited = new HashSet<>();
        q.offer(s);
        visited.add(s);
        
        boolean stopAdding = false;
        while (!q.isEmpty()) {
            String curr = q.poll();
            
            if (isValid(curr)) {
                rst.add(curr);
                stopAdding = true;
            }
            
            if (stopAdding) continue;
            
            for (int i = 0; i < curr.length(); i++) {
                if (curr.charAt(i) != '(' && curr.charAt(i) != ')') continue;
                String modified = curr.substring(0, i) + curr.substring(i + 1, curr.length());
                if (!visited.contains(modified)) {
                    q.offer(modified);
                    visited.add(modified);
                }
            }
        }
        return rst;
    }
   
    private boolean isValid(String s) {
        int count = 0;
        int i = 0;
        while (i < s.length()) {
            if (s.charAt(i) == '(') count++;
            if (s.charAt(i) == ')') count--;
            if (count < 0) return false;
            i++;
        }
        return count == 0;
    }
}

394. Decode String
这道题从这个例子s = "3[a2[c]]",可以看出是一个递归比较合适的结构。

解法一:recursion
感觉这道题不太适合用递归,想不到什么方法能够不用全局变量。主要是不知道对subStr进行递归后,指针的终止位置在哪里,只要用一个全局变量postion。

解法二:stack
要想到用两个stack,这样会方便许多。count用一个stack,因为当第二个number出现的时候,第一个还没法处理。然后就是需要另一个stack
存当前的字符串,每次遇到']’的时候,就是进行repeat的时候了,这时候要把之前处理的结果pop出来:
要搞清楚什么时候push,什么时候pop,要多练几遍。
回复

使用道具 举报

🔗
Enalynn 2019-2-18 11:47:18 | 只看该作者
全局:
实在刷不动就找个课上上吧。自己总结还是太慢了。
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-19 11:42:04 | 只看该作者
全局:
Day 14 - 2019/02/18

339. Nested List Weight Sum
嵌套结构很自然想到递归

364. Nested List Weight Sum II
关键在于加内层的时候,外层的数跟着再加一遍。只写了一个递归的解法。下次还可以练练BFS或者别的

547. Friend Circles
虽然一看就是个并查集的题,但是还是用DFS练练
看似是个二维数组的DFS, 但其实不同,值得做一下。

679. 24 Game
非常好的练习回溯法的题,要多写几遍。
关键点一:怎么处理  4 / (1 - 2/3) = 12.这样的? 用Double就可以
关键点二: 从定义出发。将两数加减乘除的结果放入list,进行递归。
还有就是别忘了不能除以0。

这个题的时间复杂度有一个hard limit
There are only 4 cards and only 4 operations that can be performed. Even when all operations do not commute, that gives us an upper bound of 12 * 6 * 2 * 4 * 4 * 4 = 921612∗6∗2∗4∗4∗4=9216 possibilities

690. Employee Importance
嵌套结构的简单递归

130. Surrounded Regions
二维矩阵上的DFS,注意如何写的简洁。

542. 01 Matrix
简单图的最短路径显然BFS ,时间复杂度O(mn)
这道题在面试的时候,O(m^2*n^2)暴力法也应该讲一下, 然后再优化到BFS或者记忆化搜索
记忆化搜索或者DP都需要有方向性,这个题的初始化和方向性都不太好想,答案中的初始化有点取巧,我觉着还是只掌握BFS就行了。
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-20 11:43:26 | 只看该作者
全局:
Day 15 - 2019/02/19

753. Cracking the Safe
两个长度为n的密码最好能共享n-1个数字,这样累加出来的钥匙串才最短的。这就是所谓的k元德布鲁因序列。不知道到时候该如何解释。
总之就是这么一个DFS,先把n个0加进去,取后n-1位的substr作为生成下一个密码的基础,然后分别加入0到k-1的其中一个字符,检查这个新密码有没有出现过,如果没有,就加入rst,然后非常非常关键的是,并不需要回溯,而是继续走下去。所以我就不知道如何解释正确性了。

638. Shopping Offers
要满足两个限制条件:
1)不用某个offer的条件是超不超数量
2)和最低总价打擂台

这道题的关键是:每一次要用offer的时候,都要和(当前needs下)不用offer的购买价格相比较。
对于给定的needs,会有重复计算,所以DP的解法是每次记录一下给定needs的最小cost。

这道题是相对比较复杂的回溯法,显然这道题还有DP的解法。

546. Remove Boxes
做这道题的时候发现了自己思路上的一个问题,初次见到一道题的时候,总想往已知的算法上去套,套不上就觉着没办法了。其实,见到问题之后,应该从问题的定义出发。先从暴力的解法开始思考,然后逐步优化,遵循这样的顺序,也能更好的理解常用的算法。

这道题显然需要用到记忆化搜索,但是这个memory很难设计,看一下是一两年前腾迅的题,就先不研究这道题的DP了。

489. Robot Room Cleaner
这道题有一点OOD的感觉。
需要会把位置和方向转化成代码中的参数:
1)由于我们并不知道初始位置,不管机器人一开始在哪里,我们设定这个点就是[0, 0]点。 2)然后就是我们需要判断目前的方向,并且表示转向后的方向。 能把这两个问题解决,就做出来一半了。

接下来就是回溯法了。也是解决两个问题:
1)如何回到原来状态;
2)如何探索下一个方向。

417. Pacific Atlantic Water Flow
没有涉及最短什么的,所以BFS/DFS都可以。需要一点脑筋急转弯,就是从boundary出发,这是比较特别的。

494. Target Sum
这道题直接DFS的时间复杂度是O(2^n),有很多重复计算,所以要记忆化搜索。关键点在于mem里存的什么。
用DP方法就更能体会出这道题是道组合类的问题。
但是能推导出来这个实在是厉害: Find a subset P of nums such that sum(P) = (target + sum(nums)) / 2
然后这就是一道377. Combination Sum IV的变形。
回复

使用道具 举报

🔗
 楼主| Wilson_2014 2019-2-21 10:53:25 | 只看该作者
全局:
Day 16 - 2019/02/20

今天花了太多时间查怎么换机油,需要买哪些工具

377. Combination Sum IV
candidates可以重复使用,sum等于target的subset的排列数
背住公式comb[target] = sum(comb[target - nums[i]])
nums = [1, 2, 3]
target = 4
comb[4] = comb[4-1] + comb[4-2] + comb[4-3] = comb[3] + comb[2] + comb[1]

529. Minesweeper
主要就是理解题意,然后就是二维矩阵上的BFS/DFS

733. Flood Fill
二维矩阵上的BFS/DFS,看清题意别粗心

979. Distribute Coins in Binary Tree
这道题就是设计好递归的定义:为了使当前tree满足要求而需要的move数。
而最终答案又不是这个定义,因为当前这个tree已经满足要求了。

968. Binary Tree Cameras
只是学习了大神的写法。这道题对于递归的定义不容易。


664. Strange Printer
这个题意理解起来不是很容易的。关键的一句是,这个打印机只能连续打相同的字符,比如aba,如果如果第一遍打的是bbb,第二个turn就只能打一个a,第三个turn再打第二个a,不能跳过b直接把两个a都打了。

第一个关键点: dp[i][j] = min(dp[i][k] + dp[k + 1][j]) for i <= k <= j - 1
第二个关键点: 初始化dp[left][right] = len;
第三个关键点: int turns = dp[left][k] + dp[k + 1][right];
                  if (s.charAt(k) == s.charAt(right)) turns--;
归类到坐标型动归吧

明天开始练习BFS的题目:

773. Sliding Puzzle
定义好状态,把问题变成一个在图上的搜索问题。
时间复杂度 = 状态总数 × 每个状态上的计算时间
状态的个数 = (n * m) 个元素的排列数 = (n * m)!
每个状态的hash值比较是 O(nm)
所以总时间就是 O(nm * (nm)!)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表