当前位置:   article > 正文

leetcode 刷题篇_f[0][0]=1; for(int i=1;i<=h;i++) { for(int s1=0;s1

f[0][0]=1; for(int i=1;i<=h;i++) { for(int s1=0;s1<(1<

1.https://leetcode-cn.com/problems/01-matrix/

第一题0-1矩阵

解法1:BFS

解法2:DP。dp的做法思路较巧妙,关键点在于二次遍历

2.https://leetcode-cn.com/problems/132-pattern

解法:最小栈。

以2,4,2,3,5为例。

从后往前遍历,构建最小栈。

5入栈

3入栈

2入栈

然后遇到4,2出栈,3出栈。3即是4右边小于3的最大值。

再遇到2,比3小得到最后结果。遍历结束。

3.https://leetcode-cn.com/problems/2-keys-keyboard/submissions/

动态规划。递推关系式: if(i%j==0) dp[i]=min(dp[i],dp[j]+i/j)。

4.https://leetcode-cn.com/problems/3sum-closest/

数之和问题的变形。

5.https://leetcode-cn.com/problems/3sum-with-multiplicity

三数之和问题的变形。

6.https://leetcode-cn.com/problems/4sum

三数之和问题的变形

7.https://leetcode-cn.com/problems/4sum-ii/

四数之和问题(II)

暴力解法的时间复杂度是四次方。

通过排序可一定程度的优化,复杂度不变。

最优解法是采用哈希表,把四重循环拆分成两个二重循环,时间复杂度仅二次方。

8.https://leetcode-cn.com/problems/accounts-merge/

合并账户和朋友圈有相似之处。

有相同邮箱的结点相连,把它们合并为一个结点即可。这样转化以后就成了朋友圈问题。

有三种解法:bfs,dfs和并查集。

9.https://leetcode-cn.com/problems/zigzag-conversion

Z字变换,找规律的问题。

10.https://leetcode.com/problems/container-with-most-water/

盛水最多的容器。贪心策略,双指针法。(一开始两根指针分别指向数组的头和尾,基于贪心策略去移动这两根指针)。这两根指针哪根指针指向的数小,便移动哪根指针。

11.https://leetcode-cn.com/problems/integer-to-roman/

输入是整数,输出是该数的罗马数字表示。

很简单,只需要把该数从大到小一直减即可,减的过程中加上被减数的罗马表示。

12.https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/

给定一个数字串,输出是可能的英文字母组合。数字和字母之间的对应关系按照电话上的来。

这题不难,但写出来还是有点耗时。

递归写法即可。

13.https://leetcode-cn.com/problems/divide-two-integers/

用位运算和减法来做除法。

如果只用减法来模拟除法的话会超时。

14.https://leetcode-cn.com/problems/validate-binary-search-tree/

易错解法:

  1. bool isValidBST(TreeNode* root)
  2. {
  3. if(root==NULL) return true;
  4. if(root->left)
  5. {
  6. if(root->left->val>=root->val) return false;
  7. }
  8. if(root->right)
  9. {
  10. if(root->right->val<=root->val) return false;
  11. }
  12. return isValidBST(root->left)&&isValidBST(root->right);
  13. }

分析这个例子即可发现上述代码的错误之处[10,5,15,null,null,6,20]。

正确的解法应该是中序遍历,若是递增序列则返回true,反之返回false。

15.https://leetcode-cn.com/problems/decode-ways/

动态规划。

16.https://leetcode-cn.com/problems/divisor-game/

动态规划解法:

  1. bool divisorGame(int N)
  2. {
  3. vector<int>dp(N,0);
  4. dp[0]=0;
  5. for(int i=1;i<N;i++)
  6. {
  7. for(int j=0;j<i;j++)
  8. {
  9. if(dp[j]==0&&(i+1)%(i-j)==0)
  10. {dp[i]=1;
  11. break;
  12. }
  13. }
  14. }
  15. return dp[N-1];
  16. }

 更简单的解法是判断N是奇数还是偶数。

分析如下:

假设当n<=N时满足奇数输偶数赢。

当n=N+1时,若N是奇数,则n是偶数。只要第一个数选择1,就赢了。

当n=N+1时,若N是偶数,则n是奇数。爱丽丝第一个数只能选择奇数,那么给鲍勃的数就是偶数。则爱丽丝输了,鲍勃赢。

17.https://leetcode-cn.com/problems/fraction-to-recurring-decimal/

本题的关键点

1.考虑正负。要把int类型转换为long long 类型。

2.找到循环的起点。

\frac{1}{7} 0.142857 又得到1 则开始循环了。

因此只要找到重复的数字就可以。

18.https://leetcode-cn.com/problems/contains-duplicate-iii/submissions/

滑动窗口。

这题是用set来维护这个滑动窗口。可以使复杂度降到N*lgK

19.https://leetcode-cn.com/problems/additive-number/submissions/

深搜。找到一条合法路径便返回。

20.https://leetcode-cn.com/problems/remove-k-digits/comments/

这题深搜会超时。19题用深搜可以剪枝,而20题无法剪枝要比较所有的情况,所以会超时。

深搜代码:

  1. string removeKdigits(string num,int k)
  2. {
  3. string ans=removeKdigits_help(num,k);
  4. ans=nofrontzero(ans);
  5. if(ans=="") return "0";
  6. return ans;
  7. }
  8. string removeKdigits_help(string num, int k)
  9. {
  10. int len=num.size();
  11. if(len==k) return "";
  12. if(k==0) return num;
  13. string s1=removeKdigits_help(num.substr(1,len-1),k-1);
  14. string s2;
  15. s2=num[0]+removeKdigits_help(num.substr(1,len-1),k);
  16. if(comparestring(s1,s2)) return s2;
  17. return s1;
  18. }
  19. string nofrontzero(string s)
  20. {
  21. int len=s.size();
  22. int i;
  23. for(i=0;i<len;i++)
  24. {
  25. if(s[i]!='0') break;
  26. }
  27. s=s.substr(i,len-i);
  28. return s;
  29. }
  30. bool comparestring(string a,string b)
  31. {
  32. a=nofrontzero(a);
  33. b=nofrontzero(b);
  34. if(a.size()<b.size()) return false;
  35. if(a.size()>b.size()) return true;
  36. if(a.size()==b.size())
  37. {
  38. int len=a.size();
  39. for(int i=0;i<len;i++)
  40. {
  41. if(a[i]<b[i]) return false;
  42. if(a[i]>b[i]) return true;
  43. }
  44. }
  45. return true;
  46. }

本题用贪心法求解:

每一步删除一个数字,执行k步就得到最终结果。

21.https://leetcode-cn.com/problems/integer-replacement/

本题用动态规划做会超时。因为动态规划做了很多无用计算。相同的思想改成递归代码即可通过。

若n为偶数,则n除以2即可。

若n为奇数,则考虑n到底是应该+1,还是-1。

此时n+1和n-1是相邻的偶数,则n+1和n-1除以2以后必然有一个是偶数,一个是奇数。

相邻的奇数和偶数之间必然有奇数的步数不小于偶数的步数。

因此选择+1或者-1后除以2仍然是偶数的那个。

22.https://leetcode-cn.com/problems/water-and-jug-problem/

水壶问题。这一题本质是个数学问题。

z<=x+y,且z是x,y的最大公约数的倍数,或者z=0满足题意。

23.https://leetcode-cn.com/problems/circular-array-loop/

环形数据循环问题。

先贴自己的代码:

  1. bool circularArrayLoop(vector<int>& nums)
  2. {
  3. int len=nums.size();
  4. vector<int>visited(len,0);
  5. for(int i=0;i<len;i++)
  6. { int start=i;
  7. vector<int>s;
  8. bool positive=nums[start]>0;
  9. while(1)
  10. {
  11. auto iter=find(s.begin(),s.end(),start);
  12. if(iter==s.end())
  13. {
  14. s.push_back(start);
  15. }
  16. else if(s.end()-iter==1) break;
  17. else return true;
  18. if((positive&&nums[start]>0)||(!positive&&nums[start]<0)&&visited[start]==0)
  19. {
  20. visited[start]=1;
  21. start+=nums[start] ;
  22. while(start>=len)
  23. start=start-len;
  24. while(start<0)
  25. start=start+len;
  26. }
  27. else break;
  28. }
  29. }
  30. return false;
  31. }

代码的思路其实已经和答案基本上是一样的。但是这段代码仍然超时了。

答案没有用vector来保存每次走的路径,而是用visited 数组+color变量来记录每次走的路径。

用时差别在find函数上。

24.https://leetcode-cn.com/problems/can-i-win

我能赢吗?这一题是典型的递归+map记录中间结果的例子。

先贴自己的代码:

  1. bool canIWin(int maxChoosableInteger, int desiredTotal)
  2. {
  3. vector<int>v;
  4. for(int i=1;i<=maxChoosableInteger;i++)
  5. {
  6. v.push_back(i);
  7. }
  8. map<vector<int>,bool>m;
  9. return dfs(v,desiredTotal,m);
  10. }
  11. bool dfs(vector<int>v,int desiredTotal,map<vector<int>,bool>&m)
  12. {
  13. vector<int>vec=v;
  14. sort(vec.begin(),vec.end());
  15. if(m.count(vec)) return m[vec];
  16. if(desiredTotal<0) return false;
  17. if(desiredTotal==0) return true;
  18. int len=v.size() ;
  19. for(int i=len-1;i>=0;i--)
  20. {
  21. int temp=v[i];
  22. auto iter=find(v.begin(),v.end(),temp);
  23. iter=v.erase(iter);
  24. if(temp>=desiredTotal||!dfs(v,desiredTotal-temp,m))
  25. {
  26. m[vec]=true;
  27. return true;
  28. }
  29. v.insert(iter,temp);
  30. }
  31. m[vec]=false;
  32. return false;
  33. }

使用dfs+map记录中间结果仍然超时了。

可以优化的地方:

对vec的排序可以略掉。用一个整数来表示这个vec。

优化的代码如下:

  1. bool canIWin(int maxChoosableInteger, int desiredTotal)
  2. {
  3. if (maxChoosableInteger >= desiredTotal) return true;
  4. if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;
  5. if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 == desiredTotal)
  6. return maxChoosableInteger%2;
  7. vector<int>v;
  8. for(int i=1;i<=maxChoosableInteger;i++)
  9. {
  10. v.push_back(i);
  11. }
  12. map<int,bool>m;
  13. return dfs(v,desiredTotal,m);
  14. }
  15. bool dfs(vector<int>v,int desiredTotal,map<int,bool>&m)
  16. { int vec=0;
  17. for(auto it:v)
  18. vec+=1<<(it-1);
  19. if(m.count(vec))
  20. return m[vec];
  21. if(desiredTotal<0) return false;
  22. if(desiredTotal==0) return true;
  23. int len=v.size() ;
  24. for(int i=len-1;i>=0;i--)
  25. {
  26. int temp=v[i];
  27. auto iter=find(v.begin(),v.end(),temp);
  28. iter=v.erase(iter);
  29. if(temp>=desiredTotal||!dfs(v,desiredTotal-temp,m))
  30. {
  31. m[vec]=true;
  32. return true;
  33. }
  34. v.insert(iter,temp);
  35. }
  36. m[vec]=false;
  37. return false;
  38. }

这并不是最优的解法。最优的解法参见答案。

25.https://leetcode-cn.com/problems/next-greater-element-iii/

下一个更大元素。这题比较简单。但是感觉题意表示不清。32位指的是比特位。

位数是个十百千位的位。

这种题注意要用long long 类型,不然会溢出。

26.https://leetcode-cn.com/problems/valid-parenthesis-string/

有效的括号字符串。

这题用暴力解法会超时。

最优解法是:考虑两种极端情况。一种是把所有的*号变成左括号,判断这个时候右括号有没有过多。

一种是把使用的*号变成右括号,判断左括号有没有过多。只要这两种极端情况满足,那么返回true,反之返回false。

27.https://leetcode-cn.com/problems/remove-comments/

删除注释。这一题其实不难,把输入转成string再处理就变简单了。一开始是直接对原始输入做处理,结果很复杂。

下面贴代码:

  1. vector<string> removeComments(vector<string>& source)
  2. {
  3. vector<string>ans;
  4. int len=source.size();
  5. string sources="";
  6. string temp="";
  7. for(int i=0;i<len;i++)
  8. {
  9. sources+=source[i]+"\n";
  10. }
  11. len=sources.size();
  12. bool lineflag=false;
  13. bool commentstartflag=false;
  14. for(int i=0;i<len;i++)
  15. {
  16. if(i+1<len&&sources[i]=='/'&&sources[i+1]=='/'&&!lineflag&&!commentstartflag)
  17. {
  18. i++;
  19. lineflag=true;
  20. continue;
  21. }
  22. if(i+1<len&&!lineflag&&sources[i]=='/'&&sources[i+1]=='*'&&!commentstartflag)
  23. {
  24. i++;
  25. commentstartflag=true;
  26. continue;
  27. }
  28. if(lineflag&&sources[i]=='\n')
  29. {
  30. lineflag=false;
  31. }
  32. if(i+1<len&&commentstartflag&&!lineflag&&sources[i]=='*'&&sources[i+1]=='/')
  33. {
  34. commentstartflag=false;
  35. i++;
  36. continue;
  37. }
  38. if(!lineflag&&!commentstartflag) temp+=sources[i];
  39. }
  40. int start=0;
  41. for(int i=0;i<temp.size();i++)
  42. {
  43. if(temp[i]=='\n')
  44. {
  45. string s=temp.substr(start,i-start);
  46. start=i+1;
  47. if(s!="") ans.push_back(s);
  48. }
  49. }
  50. return ans;
  51. }

28.https://leetcode-cn.com/problems/swap-adjacent-in-lr-string/

在LR字符串中交换相邻字符。本题是找规律题。

即L字符串只能左移,R字符串只能右移。利用这个规律来解本题。

用常规的思路:bfs会超时。

29.https://leetcode-cn.com/problems/valid-tic-tac-toe-state/

有效的井字游戏。

找规律题。

1.X的数量比O的数量多1或者是相等。

2.不可能同时X和O有 3 个相同(且非空)的字符填充任何行、列或对角线。

3.若是O有 3 个相同(且非空)的字符填充任何行、列或对角线,则X和O的数量相等。

4.若是X有 3 个相同(且非空)的字符填充任何行、列或对角线,则X比O多一个。

30.https://leetcode-cn.com/problems/friends-of-appropriate-ages/

适龄的朋友。

这一题用最常规的解法做会超时。

1 <= ages.length <= 20000.

1 <= ages[i] <= 120.

这个是本题的突破点,age的大小在2W左右,处理起来非常麻烦。如果我们把所有年龄相同的人统计起来,这最多只有120情况,因此我们可以计算 每一个年龄发送给另一个年龄的好友请求数,然后求和。这样就大大的降低了时间复杂度。

31.https://leetcode-cn.com/problems/new-21-game/

新21点

典型的动态规划问题。

dp[i]表示得分为i的概率。

递推关系式:

sum(dp[i] + dp[i - 1] + dp[i - 2] + ... + dp[i - min(i, W)]) / W。

不要用循环去求上面的和,用一个变量去记录即可。

32.https://leetcode-cn.com/problems/split-array-into-fibonacci-sequence/

将数组拆成斐波那契数列。

这一题是累加数的进阶版。累加数只判断能不能分割成斐波那契数列,而本题是返回可行的路径。若不可行,则返回空。

33.https://leetcode-cn.com/problems/longest-mountain-in-array/

数组中的最长山脉

常规的解法是O(n^{2})

优化解法是:

借用辅助数组left和right。

其中left[i]表示i的左边有多少个连续小于num[i]的元素。right[i]表示i的右边有多少个连续小于num[i]的元素。4

这样子可以把时间复杂度降到O(n)

34.https://leetcode-cn.com/problems/prime-palindrome/

回文素数。

这一题要用到两个数学性质。

1.除 11 外的偶数位回文数,都能被 11 整除

2.除 2 和 3 外,所有的素数一定在 6 的两侧

利用这两条性质可以跳过很多数字,就不会超时了。

如遇到13,则可以马上跳到101.

如遇到25,下一个可以跳到29.

35.https://leetcode-cn.com/problems/exam-room/

考场就座问题。

第一个版本答案:

  1. class ExamRoom {
  2. public:
  3. ExamRoom(int N) {
  4. vec.resize(N);
  5. for(int i=0;i<N;i++)
  6. vec[i]=-1;
  7. }
  8. int seat() {
  9. int N=vec.size();
  10. vector<int>temp;
  11. for(int i=0;i<N;i++)
  12. {
  13. if(vec[i]==i) temp.push_back(i);
  14. }
  15. if(temp.size()==0) {
  16. vec[0]=0;
  17. return 0;}
  18. if(temp.size()==1)
  19. { if(temp[0]<N/2)
  20. {vec[N-1]=N-1;
  21. return N-1;
  22. }
  23. else
  24. {
  25. vec[0]=0;
  26. return 0;
  27. }
  28. }
  29. if(temp.size()==N) return -1;
  30. int dis=0;
  31. int ans=-1;
  32. for(int i=0;i<temp.size()-1;i++)
  33. {
  34. if((temp[i+1]-temp[i])/2>dis)
  35. {dis=(temp[i+1]-temp[i])/2;
  36. ans=(temp[i+1]+temp[i])/2;
  37. }
  38. }
  39. if(vec[0]==-1&&(dis>=temp[0]/2||ans==-1))
  40. {
  41. vec[0]=0;
  42. return 0;
  43. }
  44. else if(vec[N-1]==-1&&ans==-1)
  45. {
  46. vec[N-1]=N-1;
  47. return N-1;
  48. }
  49. else
  50. {
  51. vec[ans]=ans;
  52. return ans;
  53. }
  54. }
  55. void leave(int p) {
  56. vec[p]=-1;
  57. }
  58. vector<int>vec;
  59. };

但是超时了。

优化:

由于每次调seat函数时,都要重新找哪些位置是已经有人了的,有很多重复的计算。这个部分可以优化。

优化后的代码如下:

  1. class ExamRoom {
  2. public:
  3. ExamRoom(int N) {
  4. n=N;
  5. }
  6. int seat() {
  7. if(temp.size()==0) {
  8. temp.insert(0);
  9. return 0;}
  10. if(temp.size()==1)
  11. { if(*temp.begin()<n/2)
  12. {
  13. temp.insert(n-1);
  14. return n-1;
  15. }
  16. else
  17. { temp.insert(0);
  18. return 0;
  19. }
  20. }
  21. if(temp.size()==n) return -1;
  22. int dis=0;
  23. int ans=-1;
  24. auto iter=temp.begin();
  25. while(iter!=temp.end())
  26. {
  27. auto it=iter;
  28. if(++it!=temp.end())
  29. { int first=*iter;
  30. int second=*(++iter);
  31. if((second-first)/2>dis)
  32. {
  33. dis= (second-first)/2;
  34. ans= (second+first)/2;
  35. }
  36. }
  37. else
  38. {
  39. break;
  40. }
  41. }
  42. if(temp.find(0)==temp.end()&&(dis>=*temp.begin()/2||ans==-1))
  43. {
  44. temp.insert(0);
  45. return 0;
  46. }
  47. else if(temp.find(n-1)==temp.end()&&ans==-1)
  48. {
  49. temp.insert(n-1);
  50. return n-1;
  51. }
  52. else
  53. {
  54. temp.insert(ans);
  55. return ans;
  56. }
  57. }
  58. void leave(int p) {
  59. temp.erase(p);
  60. }
  61. int n;
  62. set<int>temp;
  63. };

36.https://leetcode-cn.com/problems/decoded-string-at-index/

若把完整的字符串存储下来会内存超出。

优化解法如下:

  1. string decodeAtIndex(string S, int K)
  2. {
  3. int len=S.size();
  4. long long int size=0;
  5. for(int i=0;i<len;i++)
  6. {
  7. if(isdigit(S[i]))
  8. size=size*(S[i]-'0');
  9. else size++;
  10. }
  11. for(int i=len-1;i>=0;i--)
  12. {
  13. if((K==size||K==0)&&!isdigit(S[i])) return string("")+S[i];;
  14. if(isdigit(S[i]))
  15. {
  16. size=size/(S[i]-'0');
  17. K=K%size;
  18. }
  19. else
  20. size--;
  21. }
  22. return string("");
  23. }

先求出下来字符串的长度,再反向遍历求出第K个字符。

37.https://leetcode-cn.com/problems/bitwise-ors-of-subarrays/

这一题直接二重循环会超时。优化的思路是消去重复计算。

38.https://leetcode-cn.com/problems/sum-of-subarray-minimums

res = sum(A[i] * f(i))
where f(i) is the number of subarrays,
in which A[i] is the minimum.

难点就在于求f(i),为了求f(i)需要求left[i]和right[i]。

left[i]:A[i]左边严格大于A[i]的个数

right[i]:A[i]右边大于等于A[i]的个数

f(i) = (left[i] + 1) * (right[i] + 1),其实就是一个排列组合,左边取一个可能,那么可以从右边取right[i] + 1种来进行组合。

这里需要特别注意的一点是:首先本问题是允许重复的子数组的,这里的重复是指数字上相等,但是是不允许完全一致的区间,因此左边必须是严格大于,否则会出现重复的情况。计算left,right数组可以使用Stack在O(n)时间复杂度完成求解,最后的res计算也是线性时间,因此总的时间复杂度为O(n)。

利用单调栈来求left和right数组。

39.https://leetcode-cn.com/problems/maximum-sum-circular-subarray/

环形子数组的最大和。这一题是子数组的最大和的进阶版。

分两种情况讨论:一种是最大和没有循环。这种情况按子数组的最大和求解即可。

一种是最大和有循环。这种情况按子数组的最小和求解,再用整个数组的和减去这个最小和。

40.https://leetcode-cn.com/problems/delete-columns-to-make-sorted-ii/

贪心算法: 从前往后比较字符串上的字符, 通过删除那些破坏顺序的列来逐步构建顺序.

(S1). 用一个向量来记录当前不确定是否排好顺序的那些字符串: 让j记录当前研究的列, 若 A[i] 和 A[i+1] 的前j列完全一样, 那个 i 就包含在 vec 里. 初始化时, vec={0, 1,2,...,A.size()-2};

(S2).若 j 列破坏了之前的顺序, 那么删除 j 列, 结果加1; 若 j 列没破坏之前排序, 那么不删除, 但是新增加的 j 列可能会区分开之前不能区分的字符串 A[i][0:j-1] 和 A[i+1][0:j-1], 因此要更新 vec;

(S3).若 vec 是空的, 就说明已经排好序了, 不需要再继续了, 返回结果, 否则继续检查下一列 j+1 列.

贴代码:

  1. int minDeletionSize(vector<string>& A)
  2. {
  3. int rows=A.size();
  4. if(rows==0) return 0;
  5. int cols=A[0].size();
  6. vector<int>s;
  7. for(int i=0;i<rows-1;i++)
  8. s.push_back(i);
  9. int ans=0;
  10. for(int i=0;i<cols;i++)
  11. { bool flag=true;
  12. for(auto iter=s.begin();iter!=s.end();iter++)
  13. { if(A[*iter+1][i]<A[*iter][i])
  14. {
  15. ans++;
  16. flag=false;
  17. break;
  18. }
  19. else
  20. continue;
  21. }
  22. if(flag)
  23. {
  24. for(auto iter=s.begin();iter!=s.end();iter++)
  25. {
  26. if(A[*iter+1][i]>A[*iter][i])
  27. {
  28. iter=s.erase(iter);
  29. iter--;
  30. }
  31. }
  32. }
  33. if(s.size()==0) return ans;
  34. }
  35. return ans;
  36. }

40.https://leetcode-cn.com/problems/smallest-range-ii/

最小差值II

思路:较小的数加上K,较大的数减去K。

遍历去确定这个分割点,即可得到结果。

41.https://leetcode-cn.com/problems/online-election/

在线选举,用vector存下每个时刻是由哪个选举者主导的。

然后二分法查找即可。

42.https://leetcode-cn.com/problems/time-based-key-value-store/

这题对时间的要求非常苛刻。

  1. class TimeMap {
  2. public:
  3. /** Initialize your data structure here. */
  4. TimeMap() {
  5. }
  6. void set(string key, string value, int timestamp) {
  7. m[key].push_back(make_pair(value,timestamp));
  8. }
  9. string get(string key, int timestamp) {
  10. if(m.find(key)==m.end()) return "";
  11. auto& vec=m[key];//这个地方必须要有引用,否则会超时。
  12. int len=vec.size();
  13. int low=0;
  14. int high=len-1;
  15. int mid=(low+high)/2;
  16. while(low<=high)
  17. {
  18. if(vec[mid].second==timestamp) return vec[mid].first;
  19. else if (vec[mid].second<timestamp) low=mid+1;
  20. else high=mid-1;
  21. mid=(low+high)/2;
  22. }
  23. return high==-1? "":vec[high].first;
  24. }
  25. unordered_map<string,vector<pair<string,int>>>m;
  26. };
  27. /**
  28. * Your TimeMap object will be instantiated and called as such:
  29. * TimeMap* obj = new TimeMap();
  30. * obj->set(key,value,timestamp);
  31. * string param_2 = obj->get(key,timestamp);
  32. */

43.数独问题,深搜的典型问题。

版本一:

  1. class Solution {
  2. public:
  3. void solveSudoku(vector<vector<char>>& board)
  4. {
  5. int count=0;
  6. vector<pair<int,int>>vec;
  7. for(int i=0;i<9;i++)
  8. for(int j=0;j<9;j++)
  9. {
  10. if(board[i][j]=='.')
  11. {
  12. vec.push_back(make_pair(i,j));
  13. }
  14. }
  15. for(int num=1;num<=9;num++)
  16. {
  17. if(dfs(board,vec,num,count)) break;;
  18. }
  19. return;
  20. }
  21. private:
  22. bool dfs(vector<vector<char>>& board, vector<pair<int, int>>&vec, int num, int &count)
  23. {
  24. if (count == vec.size()) return true;
  25. int i = vec[count].first;
  26. int j = vec[count].second;
  27. if (isvalid(board, i, j, num) == false) return false;
  28. board[i][j] = num + '0';
  29. count++;
  30. bool flag = false;
  31. for (int nextnum = 1; nextnum <= 9; nextnum++)
  32. {
  33. if (dfs(board, vec, nextnum, count))
  34. {
  35. flag = true;
  36. break;
  37. }
  38. }
  39. if(!flag) board[i][j] = '.';
  40. count--;
  41. return flag;
  42. }
  43. bool isvalid(vector<vector<char>>& board, int i, int j, int num)
  44. {
  45. set<int>s;
  46. for (int k = 0; k < 9; k++)
  47. {
  48. if(k!=j) s.insert(board[i][k] - '0');
  49. }
  50. for (int k = 0; k < 9; k++)
  51. {
  52. if(k!=i) s.insert(board[k][j] - '0');
  53. }
  54. for (int m = i / 3 * 3; m <= i / 3 * 3 + 2; m++)
  55. for (int n = j / 3 * 3; n <= j / 3 * 3 + 2; n++)
  56. {
  57. if(m!=i&&n!=j)
  58. s.insert(board[m][n] - '0');
  59. }
  60. if (s.find(num) == s.end()) return true;
  61. return false;
  62. }
  63. };

结果:超时。

改进:剪枝部分可以优化。用三个数组来标记某个数字是否在某行、某列或者是某个3*3小方格中出现过。

版本二:

  1. class Solution {
  2. public:
  3. void solveSudoku(vector<vector<char>>& board)
  4. {
  5. int count = 0;
  6. vector<vector<bool>>rows(9, vector<bool>(9, false));
  7. vector<vector<bool>>cols(9, vector<bool>(9, false));
  8. vector<vector<bool>>blocks(9, vector<bool>(9, false));
  9. vector<pair<int, int>>vec;
  10. for (int i = 0; i < 9; i++)
  11. for (int j = 0; j < 9; j++)
  12. {
  13. if (board[i][j] == '.')
  14. {
  15. vec.push_back(make_pair(i, j));
  16. }
  17. else
  18. {
  19. rows[i][board[i][j] - '1'] = 1;
  20. cols[j][board[i][j] - '1'] = 1;
  21. blocks[i / 3 * 3 + j / 3][board[i][j] - '1'] = 1;
  22. }
  23. }
  24. for (int num = 1; num <= 9; num++)
  25. {
  26. if (dfs(board, vec, num, count,rows,cols,blocks)) break;
  27. }
  28. return;
  29. }
  30. private:
  31. bool dfs(vector<vector<char>>& board, vector<pair<int, int>>&vec, int num, int &count, vector<vector<bool>>&rows, vector<vector<bool>>&cols, vector<vector<bool>>&blocks)
  32. {
  33. if (count == vec.size()) return true;
  34. int i = vec[count].first;
  35. int j = vec[count].second;
  36. if (rows[i][num - 1] || cols[j][num - 1] || blocks[i / 3 * 3 + j / 3][num - 1]) return false;
  37. board[i][j] = num + '0';
  38. rows[i][num - 1] = 1;
  39. cols[j][num - 1] = 1;
  40. blocks[i / 3 * 3 + j / 3][num - 1] = 1;
  41. count++;
  42. bool flag = false;
  43. for (int nextnum = 1; nextnum <= 9; nextnum++)
  44. {
  45. if (dfs(board, vec, nextnum, count,rows,cols,blocks))
  46. {
  47. flag = true;
  48. break;
  49. }
  50. }
  51. if (!flag)
  52. {
  53. board[i][j] = '.';
  54. rows[i][num - 1] = 0;
  55. cols[j][num - 1] = 0;
  56. blocks[i / 3 * 3 + j / 3][num - 1] = 0;
  57. }
  58. count--;
  59. return flag;
  60. }
  61. };

44.缺失的第一个正数

限制:时间复杂度 O(n)  空间复杂度 常数复杂度

思路:   桶排序 。把i放在下标为i-1的位置上,然后顺序遍历一遍找到第一个不满足的元素即可。

45.有效数字https://leetcode-cn.com/problems/valid-number/

解法:有限状态自动机。

46.https://leetcode-cn.com/problems/minimum-window-substring/

双指针法

47.柱状图中的最大矩形

https://leetcode-cn.com/problems/largest-rectangle-in-histogram/

解法:单调非递减栈

48.最大矩形

https://leetcode-cn.com/problems/maximal-rectangle/

解法:转化为上一题.

49.计算右侧小于当前元素的个数

https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/

树状数组.复杂度:O(nlgn)

50.去除重复字母

https://leetcode-cn.com/problems/remove-duplicate-letters/

贪心法.

51.拼接最大数

https://leetcode-cn.com/problems/create-maximum-number/

单调栈得到数组长度为k的最大子序列

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/432610
推荐阅读
相关标签