leetcode 刷题篇

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/

易错解法:

 bool isValidBST(TreeNode* root) 
    {
     if(root==NULL)   return true;
     if(root->left)
     {
         if(root->left->val>=root->val) return false;
     }
     if(root->right)
     {
         if(root->right->val<=root->val) return false;
     } 
    return isValidBST(root->left)&&isValidBST(root->right);
    }

分析这个例子即可发现上述代码的错误之处[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/

动态规划解法:

  bool divisorGame(int N) 
    {
     vector<int>dp(N,0);
     dp[0]=0;
     for(int i=1;i<N;i++)
     {  
         for(int j=0;j<i;j++)
         {
             if(dp[j]==0&&(i+1)%(i-j)==0)
             {dp[i]=1;
              break;
             }
         }
         
    }
        return dp[N-1];
    }

 更简单的解法是判断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题无法剪枝要比较所有的情况,所以会超时。

深搜代码:

  string removeKdigits(string num,int k)
{
	string ans=removeKdigits_help(num,k);
	ans=nofrontzero(ans);
    if(ans=="") return "0";
	return ans;
}
string removeKdigits_help(string num, int k) 
{
    
	int len=num.size();
    if(len==k) return "";
    if(k==0) return num;
    string s1=removeKdigits_help(num.substr(1,len-1),k-1);
	string s2;
    
	s2=num[0]+removeKdigits_help(num.substr(1,len-1),k);
	
    
    if(comparestring(s1,s2)) return s2;
    return s1;
}
string nofrontzero(string s)
{
    int len=s.size();
    int i;
    for(i=0;i<len;i++)
    {
    if(s[i]!='0') break;
    }
    s=s.substr(i,len-i);
	return s;
}
bool comparestring(string a,string b)
{
     a=nofrontzero(a);
	 b=nofrontzero(b);
	 if(a.size()<b.size())  return false;
     if(a.size()>b.size())  return true;
     if(a.size()==b.size()) 
     {
         int len=a.size();
         for(int i=0;i<len;i++)
         {
          if(a[i]<b[i]) return false;
          if(a[i]>b[i]) return true;
         }
    
     }
       return true; 
}

本题用贪心法求解:

每一步删除一个数字,执行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/

环形数据循环问题。

先贴自己的代码:

bool circularArrayLoop(vector<int>& nums) 
    {
      int len=nums.size();
      vector<int>visited(len,0);
      for(int i=0;i<len;i++)
      {     int start=i;
            vector<int>s;
            bool positive=nums[start]>0;
            
          while(1)
          {
             auto iter=find(s.begin(),s.end(),start);
             if(iter==s.end()) 
             {
                 
                 s.push_back(start);
             }
             else if(s.end()-iter==1) break;
             else return true;
             if((positive&&nums[start]>0)||(!positive&&nums[start]<0)&&visited[start]==0)
             {
             visited[start]=1; 
             start+=nums[start] ;
             
             while(start>=len)
             start=start-len;
             while(start<0)
             start=start+len;
             }
             else break;
             
            
          }
      }
      return false;
    }

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

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

用时差别在find函数上。

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

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

先贴自己的代码:

 bool canIWin(int maxChoosableInteger, int desiredTotal) 
    {
      vector<int>v;
        for(int i=1;i<=maxChoosableInteger;i++)
        {
            v.push_back(i);
        }
        map<vector<int>,bool>m;
        return dfs(v,desiredTotal,m);
    }
    bool dfs(vector<int>v,int desiredTotal,map<vector<int>,bool>&m)
    {
        vector<int>vec=v;
        sort(vec.begin(),vec.end());
        if(m.count(vec)) return m[vec];
        if(desiredTotal<0) return false;
        if(desiredTotal==0) return true;
        int len=v.size()   ;
        for(int i=len-1;i>=0;i--)
        {
            int temp=v[i];
            auto iter=find(v.begin(),v.end(),temp);
            iter=v.erase(iter);
            if(temp>=desiredTotal||!dfs(v,desiredTotal-temp,m)) 
            {  
             m[vec]=true;
            return true;
            }
            v.insert(iter,temp);
        }
        m[vec]=false;
        return false;
    }

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

可以优化的地方:

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

优化的代码如下:

bool canIWin(int maxChoosableInteger, int desiredTotal) 
    {
       if (maxChoosableInteger >= desiredTotal) return true;
        if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 < desiredTotal) return false;
        if (maxChoosableInteger * (maxChoosableInteger + 1) / 2 == desiredTotal) 
            return maxChoosableInteger%2;

        vector<int>v;
        for(int i=1;i<=maxChoosableInteger;i++)
        {
            v.push_back(i);
        }
        
        map<int,bool>m;
        return dfs(v,desiredTotal,m);
    }
    bool dfs(vector<int>v,int desiredTotal,map<int,bool>&m)
    {   int vec=0;
        for(auto it:v)
          vec+=1<<(it-1);  
        if(m.count(vec)) 
          return m[vec];
        if(desiredTotal<0) return false;
        if(desiredTotal==0) return true;
        int len=v.size()   ;
        for(int i=len-1;i>=0;i--)
        {
            int temp=v[i];
            auto iter=find(v.begin(),v.end(),temp);
            iter=v.erase(iter);
            if(temp>=desiredTotal||!dfs(v,desiredTotal-temp,m)) 
            {  
             m[vec]=true;
            return true;
            }
            v.insert(iter,temp);
        }
        m[vec]=false;
        return false;
    }

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

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再处理就变简单了。一开始是直接对原始输入做处理,结果很复杂。

下面贴代码:

  vector<string> removeComments(vector<string>& source) 
{
     vector<string>ans;
     int len=source.size();
     string sources="";
     string temp="";
     for(int i=0;i<len;i++)
     {
       sources+=source[i]+"\n";
     }
   
     len=sources.size();
     bool lineflag=false;
     bool commentstartflag=false;
     for(int i=0;i<len;i++)
     {
      if(i+1<len&&sources[i]=='/'&&sources[i+1]=='/'&&!lineflag&&!commentstartflag)
      {
      i++;
      lineflag=true;
      continue;
      }
      if(i+1<len&&!lineflag&&sources[i]=='/'&&sources[i+1]=='*'&&!commentstartflag)
      {
        i++;
        commentstartflag=true;
        continue;
      }
      if(lineflag&&sources[i]=='\n')
      {
        lineflag=false;
      }
      if(i+1<len&&commentstartflag&&!lineflag&&sources[i]=='*'&&sources[i+1]=='/')
      {
       commentstartflag=false;
       i++;
       continue;
      }

      if(!lineflag&&!commentstartflag) temp+=sources[i];
      
     }
     int start=0;
     for(int i=0;i<temp.size();i++)
     {
     if(temp[i]=='\n') 
     {
     string s=temp.substr(start,i-start); 
     start=i+1;
     if(s!="") ans.push_back(s);
     }
     }
    return ans;
     
}

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/

考场就座问题。

第一个版本答案:

class ExamRoom {
public:
    ExamRoom(int N) {
    vec.resize(N);
    for(int i=0;i<N;i++)
        vec[i]=-1;
    }
    int seat() {
    int N=vec.size();
    vector<int>temp;
    for(int i=0;i<N;i++)
    {
        if(vec[i]==i) temp.push_back(i);
    }
    if(temp.size()==0) {
        vec[0]=0;
        return 0;}
    if(temp.size()==1) 
    { if(temp[0]<N/2)  
      {vec[N-1]=N-1;
      return N-1;
      }
    else
    {
       vec[0]=0;
       return 0;
    }
    }
    if(temp.size()==N) return -1;
    int dis=0;
    int ans=-1;
    for(int i=0;i<temp.size()-1;i++)
    {
        if((temp[i+1]-temp[i])/2>dis) 
        {dis=(temp[i+1]-temp[i])/2;
        ans=(temp[i+1]+temp[i])/2;
        }
    }
    if(vec[0]==-1&&(dis>=temp[0]/2||ans==-1))
    {
        vec[0]=0;
        return 0;
    }
    else if(vec[N-1]==-1&&ans==-1)
    {
        vec[N-1]=N-1;
        return N-1;
    }
    else    
    {
       vec[ans]=ans;
       return ans;
    }
    }
    void leave(int p) {
     vec[p]=-1;
    }
    vector<int>vec;
};

但是超时了。

优化:

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

优化后的代码如下:

class ExamRoom {
public:
    ExamRoom(int N) {
    n=N;
    }
    int seat() {
   if(temp.size()==0) {
    temp.insert(0);
    return 0;}
    if(temp.size()==1) 
    { if(*temp.begin()<n/2)  
      {
       temp.insert(n-1);
      return n-1;
      }
    else
    { temp.insert(0);
       return 0;
    }
    }
    if(temp.size()==n) return -1;
    int dis=0;
    int ans=-1;
    auto iter=temp.begin();
   while(iter!=temp.end())
    {
      auto it=iter;
    if(++it!=temp.end())
    {  int first=*iter;
      int second=*(++iter);
        if((second-first)/2>dis)
       {
        dis= (second-first)/2;
        ans= (second+first)/2;
       }
    }
    else
    {
       break;
    }
    
    }
    if(temp.find(0)==temp.end()&&(dis>=*temp.begin()/2||ans==-1))
    {
    temp.insert(0);
    return 0;    
    }
    else if(temp.find(n-1)==temp.end()&&ans==-1)
    {
       
        temp.insert(n-1);
        return n-1;
    }
     else    
    {
      
       temp.insert(ans);
       return ans;
    }
    }
    void leave(int p) {
    
    temp.erase(p);
     
    }
    int n;
    set<int>temp;
};

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

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

优化解法如下:

 string decodeAtIndex(string S, int K) 
    {
      int len=S.size();
      long long int size=0;
      for(int i=0;i<len;i++)
      {
        if(isdigit(S[i]))
            size=size*(S[i]-'0');
        else size++;
      }
     for(int i=len-1;i>=0;i--)
     {
        if((K==size||K==0)&&!isdigit(S[i]))  return string("")+S[i];;
         if(isdigit(S[i]))
         {
             size=size/(S[i]-'0');
             K=K%size;
         }
         else
            size--;
     }
        return string("");
    }

先求出下来字符串的长度,再反向遍历求出第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 列.

贴代码:

int minDeletionSize(vector<string>& A) 
 {
      int rows=A.size();
      if(rows==0) return 0;
      int cols=A[0].size();
      vector<int>s;
      for(int i=0;i<rows-1;i++)
       s.push_back(i);
      int ans=0;
     for(int i=0;i<cols;i++)
      { bool flag=true;
        for(auto iter=s.begin();iter!=s.end();iter++)
        { if(A[*iter+1][i]<A[*iter][i])
             {
               ans++;
               flag=false;
               break; 
             }
            else
               continue;
         }
         if(flag)
         {
          for(auto iter=s.begin();iter!=s.end();iter++)
          {
              if(A[*iter+1][i]>A[*iter][i])
             {
               iter=s.erase(iter);
               iter--;
             }
          }
         }
         if(s.size()==0) return ans;
        }
  return ans;
 }

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/

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

class TimeMap {
public:
    /** Initialize your data structure here. */
    TimeMap() {
        
    }
    
    void set(string key, string value, int timestamp) {
   
     m[key].push_back(make_pair(value,timestamp));
     
    }
    
    string get(string key, int timestamp) {
      
      if(m.find(key)==m.end()) return "";
      auto& vec=m[key];//这个地方必须要有引用,否则会超时。
      int len=vec.size();
      int low=0;
      int high=len-1;
      int mid=(low+high)/2;
      while(low<=high)
      {
       if(vec[mid].second==timestamp) return vec[mid].first;
       else if (vec[mid].second<timestamp) low=mid+1;
       else high=mid-1;
       mid=(low+high)/2;
      }
      return high==-1? "":vec[high].first;
     }
    unordered_map<string,vector<pair<string,int>>>m;
};

/**
 * Your TimeMap object will be instantiated and called as such:
 * TimeMap* obj = new TimeMap();
 * obj->set(key,value,timestamp);
 * string param_2 = obj->get(key,timestamp);
 */

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

版本一:

class Solution {
public:
    void solveSudoku(vector<vector<char>>& board) 
    {
      int count=0;
      vector<pair<int,int>>vec;
      for(int i=0;i<9;i++)
          for(int j=0;j<9;j++)
          {
              if(board[i][j]=='.') 
              {
               vec.push_back(make_pair(i,j));
              }
          }
      for(int num=1;num<=9;num++)
      {
          if(dfs(board,vec,num,count)) break;;
       
      }
      return;
    }
private:
  bool dfs(vector<vector<char>>& board, vector<pair<int, int>>&vec, int num, int &count)
{
	if (count == vec.size()) return true;
	int i = vec[count].first;
	int j = vec[count].second;
	
	if (isvalid(board, i, j, num) == false) return false;
	board[i][j] = num + '0';
	count++;
	bool flag = false;
	for (int nextnum = 1; nextnum <= 9; nextnum++)
	{
		if (dfs(board, vec, nextnum, count))
		{
			flag = true;
			break;
		}
	}
	if(!flag) board[i][j] = '.';
	count--;
	return flag;
}
    bool isvalid(vector<vector<char>>& board, int i, int j, int num)
   {
	set<int>s;
	for (int k = 0; k < 9; k++)
	{
		if(k!=j) s.insert(board[i][k] - '0');
	}
	
	
	for (int k = 0; k < 9; k++)
	{
		if(k!=i) s.insert(board[k][j] - '0');
	}

	for (int m = i / 3 * 3; m <= i / 3 * 3 + 2; m++)
		for (int n = j / 3 * 3; n <= j / 3 * 3 + 2; n++)
		{
			if(m!=i&&n!=j)
			s.insert(board[m][n] - '0');
		}
	if (s.find(num) == s.end()) return true;
	return false;
  }

};

结果:超时。

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

版本二:

class Solution {
public:
   void solveSudoku(vector<vector<char>>& board)
{
	int count = 0;
    vector<vector<bool>>rows(9, vector<bool>(9, false));
    vector<vector<bool>>cols(9, vector<bool>(9, false));
    vector<vector<bool>>blocks(9, vector<bool>(9, false));
	vector<pair<int, int>>vec;
	for (int i = 0; i < 9; i++)
		for (int j = 0; j < 9; j++)
		{
			if (board[i][j] == '.')
			{
			vec.push_back(make_pair(i, j));
			}
			else
			{
				rows[i][board[i][j] - '1'] = 1;
				cols[j][board[i][j] - '1'] = 1;
				blocks[i / 3 * 3 + j / 3][board[i][j] - '1'] = 1;
			}
		}
	for (int num = 1; num <= 9; num++)
	{
		if (dfs(board, vec, num, count,rows,cols,blocks)) break;

	}
	return;
}
private:
    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)
{
	if (count == vec.size()) return true;
	int i = vec[count].first;
	int j = vec[count].second;
	if (rows[i][num - 1] || cols[j][num - 1] || blocks[i / 3 * 3 + j / 3][num - 1]) return false;
	
	board[i][j] = num + '0';
	rows[i][num - 1] = 1;
	cols[j][num - 1] = 1;
	blocks[i / 3 * 3 + j / 3][num - 1] = 1;
	count++;
	bool flag = false;
	for (int nextnum = 1; nextnum <= 9; nextnum++)
	{
		if (dfs(board, vec, nextnum, count,rows,cols,blocks))
		{
			flag = true;
			break;
		}
	}
	if (!flag)
	{
		board[i][j] = '.';
		rows[i][num - 1] = 0;
		cols[j][num - 1] = 0;
		blocks[i / 3 * 3 + j / 3][num - 1] = 0;
	}
	count--;
	return flag;
}

};

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的最大子序列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 二分法 5 1.1. 什么是二分查找 5 1.2. 如何识别二分法 5 1.3. 二分法模板 6 1.3.1. 模板一 6 1.3.1.1. 模板代码 6 1.3.1.2. 关键属性 7 1.3.1.3. 语法说明 7 1.3.1.4. Lc69:x的平方根 8 1.3.1.5. Lc374:猜数大小 9 1.3.1.6. Lc33:搜索旋转数组 11 1.3.2. 模板二 13 1.3.2.1. 模板代码 13 1.3.2.2. 关键属性 14 1.3.2.3. 语法说明 14 1.3.2.4. Lc278:第一个错误版本 14 1.3.2.5. Lc162:寻找峰值 16 1.3.2.6. Lc153:寻找旋转排序数组最小值 19 1.3.2.7. Lc154:寻找旋转排序数组最小值II 20 1.3.3. 模板三 22 1.3.3.1. 模板代码 22 1.3.3.2. 关键属性 23 1.3.3.3. 语法说明 23 1.3.3.4. LC-34:在排序数组中查找元素的第一个和最后一个 23 1.3.3.5. LC-658:找到K个最接近的元素 25 1.3.4. 小结 28 1.4. LeetCode中二分查找题目 29 2. 双指针 30 2.1. 快慢指针 31 2.1.1. 什么是快慢指针 31 2.1.2. 快慢指针模板 31 2.1.3. 快慢指针相关题目 32 2.1.3.1. LC-141:链表是否有环 32 2.1.3.2. LC-142:环形链表入口 34 2.1.3.3. LC-876:链表的中间节点 37 2.1.3.4. LC-287:寻找重复数 40 2.2. 滑动窗口 43 2.2.1. 什么是滑动窗口 43 2.1.4. 常见题型 44 2.1.5. 注意事项 45 2.1.6. 滑动窗口模板 45 2.1.7. 滑动窗口相关题目 46 2.1.7.1. LC-3:无重复字符的最长子串 47 2.1.7.2. LC-76:最小覆盖子串 49 2.1.7.3. LC-209:长度最小的子数组 54 2.1.7.4. LC-239:滑动窗口最大值 57 2.1.7.5. LC-395:至少有K个重复字符的最长子串 60 2.1.7.6. LC-567:字符串排列 62 2.1.7.7. LC-904:水果成篮 64 2.1.7.8. LC-424:替换后的最长重复字符 66 2.1.7.9. LC-713:乘积小于K的子数组 67 2.1.7.10. LC-992:K个不同整数的子数组 70 2.3. 左右指针 73 2.3.1. 模板 73 2.3.2. 相关题目 73 2.3.2.1. LC-76:删除倒数第N个节点 74 2.3.2.2. LC-61:旋转链表 76 2.3.2.3. LC-80:删除有序数组中的重复项 79 2.3.2.4. LC-86:分割链表 80 2.3.2.5. LC-438:找到字符串中所有字母的异位词 82 3. 模板 85 2.3.2.6. LC-76:删除倒数第N个节点 85
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值