化悲痛为力量——暑假刷题走起

6.21

【思维】接雨水-力扣

题目描述不贴了,在上面的链接里↑

  第一遍写的思路过于简单,按每层遍历,还可以递归少写点代码。但时间复杂度O(n*n),导致在复杂数据点超时。
  参考了windliang的题解才想到可以按列遍历,每个柱子能储存的雨水只和左边所有柱子的最高lmax,与右边所有最高rmax有关。两者中的较小者min减去该柱子的高度h得到的结果和0相比的较大值就是答案。如果这个差小于等于0,就应该等于0。
  进一步还可以用单调栈储存数据,使空间复杂度再次降低。(这里下次好好研究一下)

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int trap(vector<int>& height) {
 4         int rmax=0,lmax=0,len=height.size(),sum=0;
 5         int Max1[100000],Max2[100000];
 6         for(int i=0;i<len;++i){
 7             if(i>0) rmax=max(rmax,height.at(i-1));
 8             Max1[i]=rmax;
 9         }
10         for(int i=len-1;i>=0;--i){
11             if(i+1<len) lmax=max(lmax,height.at(i+1));
12             Max2[i]=lmax;
13         }
14         for(int i=0;i<len;++i){
15             int tmp=min(Max1[i],Max2[i]);
16             sum+=max(tmp-height.at(i),0);
17         }
18        return sum;
19     }
20 };
View Code
复制代码

6.22

【思维】模式匹配-力扣

题目描述在上面的链接里↑  

  一开始想了三个思路。①枚举,搜索匹配串中重复出现的子串。如果有重复的子串可能性多,则效率太低,pass;②从匹配串入手,看能匹配什么模式,再查模式串是否是其中一种情况。实际上与①本质相同,pass;③意识到匹配题最好从模式串入手,结合基本计算,匹配串的可能组合就是有限的,可行。

  核心:解不定方程。anum*alen + bnum*blen=vlen => anum和bnum可以从模式串p中数出、作系数,alen和blen相当于未知数

  特殊情况:重复子串a_re和b_re不能相等,但可以有一个为空串;对于anum和bnum有一个为0、都为0的情况要提前讨论。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     bool patternMatching(string pattern, string value) {
 4         string p=pattern, v=value;
 5         int plen=p.length(), vlen=v.length(), tmp=0, anum=0, bnum=0;
 6         for(int i=0;i<plen;++i){
 7             if(p[i]=='a') anum++;
 8             else bnum++;
 9         }
10 //根据a和b的数量以及目标串的长度,解二元一次方程    
11         if(anum+bnum==0){
12             if(v.length()!=0) return false;
13             return true;
14         }
15         if(anum==0||bnum==0){
16             int num=anum+bnum;
17             if( vlen%num !=0) return false;
18             string tmp,re;
19             re.assign(v, 0, vlen/num);
20             for(int i=0;i<vlen;i+=vlen/num){
21                 tmp.assign(v, i, vlen/num);
22                 if(tmp!=re) return false;
23             }
24             return true;
25         }
26         for(int i=0; i<=(vlen/anum); ++i){
27             if( (vlen-i*anum)%bnum==0 ){
28                 int alen=i, blen=(vlen-i*anum)/bnum;
29                 string tmp, re_a, re_b;
30                 int ptr=0;//比对指针 
31                 bool a_occur=false, b_occur=false, find=true;
32                 for(int j=0;j<plen;++j){
33                     if(a_occur && b_occur && re_a==re_b) break;
34                     if(p[j]=='a'){
35                         tmp.assign(v,ptr,alen);
36                         ptr+=alen;
37                         if(!a_occur){
38                             re_a=tmp;
39                             a_occur=1;
40                         }
41                         else{
42                             if(tmp!=re_a){
43                                 find=false;
44                                 break;
45                             }
46                         }
47                     }
48                     else{
49                         tmp.assign(v,ptr,blen);
50                         ptr+=blen;
51                         if(!b_occur){
52                             re_b=tmp;
53                             b_occur=1;
54                         }
55                         else{
56                             if(tmp!=re_b){
57                                 find=false;
58                                 break;
59                             }
60                         }
61                     }
62                 }
63                 if(re_a!=re_b && find) return true;
64             }
65         }
66         return false;
67     }
68 };
View Code
复制代码

 6.23

【手感-进制计算】二进制求和-力扣

今天忙着投实习,刷题太水了(这个借口真烂x)

  这道是简单题,一遍读懂题意很重要。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     string addBinary(string a, string b) {
 4         string ans="";
 5         int alen=a.length(), blen=b.length();
 6         int p1=alen-1, p2=blen-1, res=0;
 7         while(p1>=0 || p2>=0){
 8             if(p1>=0) res+=a[p1]-'0';
 9             if(p2>=0) res+=b[p2]-'0';
10             string tmp="x";
11             tmp[0]=res%2+'0';
12             ans=tmp+ans;
13             res/=2;
14             p1--;
15             p2--;
16         }
17         while(res>0){
18             string tmp="x";
19             tmp[0]=res%2+'0';
20             ans=tmp+ans;
21             res/=2;           
22         }
23         int cnt=0;
24         if(ans[0]=='0'){
25             for(int i=0; i<ans.length(); ++i){
26                 if(i==ans.length()-1){
27                     string tmp="0";
28                     tmp[0]=ans[ans.length()-1];
29                     return tmp;
30                 }
31                 if(ans[i]!='0') break;
32                 else cnt++;
33             }
34         }
35         ans.assign(ans, cnt, ans.length()-cnt);
36         return ans;
37     }
38 };
View Code
复制代码

 6.24

【双指针】最接近的三数之和-力扣

  因为是三数之和、且不是求相等而是相近,用二重循环+二分排序查找似乎比双指针慢很多,但两者都要注意边界情况( |pb-pc| ==1时以及到达此状态前一刻的情况),可以多建几个临时变量储存结果。

参考代码:

复制代码
 1 //①排序+二分查找法
 2 class Solution {
 3 public:
 4     int threeSumClosest(vector<int>& nums, int target) {
 5         sort(nums.begin(),nums.end());
 6         int a, b, c, vlen=nums.size();
 7         int minloc[3]={0};
 8         for(int i=vlen-1;i>=0;--i){
 9             for(int j=i-1;j>=0;--j){
10                 a=nums.at(i);
11                 b=nums.at(j);
12                 c=target-a-b;
13                 int r=0, l=j-1;
14                 if(l<0) break;
15                 while(l-r>1){
16                     if( abs( nums.at(r)-c ) > abs( nums.at(l)-c )){
17                         r=(r+l)/2;
18                     }
19                     else{
20                         l=(r+l)/2;
21                     }
22                 }
23                 if( abs( nums.at(r)-c ) > abs( nums.at(l)-c )) r=l;
24                 if((i==vlen-1 && j==vlen-2) || abs(nums.at(minloc[0])+nums.at(minloc[1])+nums.at(minloc[2])-target)>abs(nums.at(i)+nums.at(j)+nums.at(r)-target)){
25                     minloc[2]=r;
26                     minloc[0]=i;
27                     minloc[1]=j;
28                 }
29             }
30         }
31         return nums.at(minloc[0])+nums.at(minloc[1])+nums.at(minloc[2]);
32     }
33 };
34 
35 //②排序+双指针法
36 class Solution {
37 public:
38     int threeSumClosest(vector<int>& nums, int target) {
39         sort(nums.begin(),nums.end());
40         int vlen=nums.size(), pb, pc, sum, ans=1<<30;
41         for(int i=vlen-1;i>=0;--i){
42             pb=i-1;pc=0;
43             if(pb<=0) break;
44             while(pb-pc>1){
45                 sum=nums.at(i)+nums.at(pb)+nums.at(pc);
46                 if( sum==target ) return target;
47                 if( sum>target ) pb--;
48                 else pc++;
49             }
50             int sum2=nums.at(i)+nums.at(pb)+nums.at(pc);
51             if( i>2 && abs(sum2-target)<abs(sum-target) ) sum=sum2;
52             else if(i<=2) sum=sum2;
53             if( abs(sum-target)<abs(ans-target) ) ans=sum;
54         }
55         return ans;
56     }
57 };
View Code
复制代码

 6.25

【动规】单词拆分-力扣

  这道题有点意思,题意很简单,在字典中查找、匹配,问是否能用字典词组成目标串。一开始的思路是对字典排序+二分查找起始点(首字母与当前待匹配字符串首字母相同的字典词)+递归,但超时了。然后动规,建一个set,只储存匹配不到的子字符串(能匹配到的一定是答案,肯定已经return true了),每次递归前先查是否该字符串在set里,是则直接return false。

  另外,有个局部优化是要先贪心匹配最长的字典单词。试了一下,将二分查找到的位置记为r。
  ①未优化的写法是从r开始向两边±i(i=0,1,2,3……)地搜索,往下递归,两边都越界或都不再匹配则退出循环;
  ②优化后,从r开始往后找(sort函数默认按字典序排序,头部相同,尾部更长的单词在后面),找到最后一个首字母能匹配上的位置maxloc,然后再从maxloc往前遍历,每一层向下递归。

  参考代码中写了个小函数bool HeadOf(string A, string B)来判断是否A是B的头部。

参考代码:

复制代码
 1 //①动规-未优化方法
 2 class Solution {
 3 public:
 4     set<string> fail;
 5     bool HeadOf(string A, string B){
 6         if(A.length()>B.length()) return false;
 7         for(int i=0;i<A.length();++i){
 8             if(A[i]!=B[i]) return false;
 9         }
10         return true;
11     }
12     bool wordBreak(string s, vector<string>& wordDict) {
13         auto p=fail.find(s);
14         if(p!=fail.end()) return false;
15         if(s=="") return true;
16         sort(wordDict.begin(), wordDict.end());
17         int wlen=wordDict.size(), slen=s.length();
18         if(wlen==0){
19             fail.insert(s);
20             return false;
21         }
22         int r=0, l=wlen-1, maxloc=-1;
23         while(l-r>1){
24             if( wordDict.at( (r+l)/2 )[0] < s[0]) r=(r+l)/2;
25             else l=(r+l)/2;
26         }
27         if( wordDict.at(r)[0]==s[0] || wordDict.at(l)[0]==s[0]){
28             for(int i=0;;i++){
29                 if(r+i>=wlen && r-i<0) break;
30                 if(r+i<wlen && wordDict.at(r+i)[0]==s[0] && HeadOf(wordDict.at(r+i),s) ){
31                     string tmp;
32                     tmp.assign(s,wordDict.at(r+i).length(),slen-wordDict.at(r+i).length());
33                     if(wordBreak(tmp,wordDict)) return true;
34                 }
35                 if(i!=0 && r-i>=0 && wordDict.at(r-i)[0]==s[0] && HeadOf(wordDict.at(r-i),s)){
36                     string tmp;
37                     tmp.assign(s,wordDict.at(r-i).length(),slen-wordDict.at(r-i).length());
38                     if(wordBreak(tmp,wordDict)) return true;
39                 }
40             }
41         }
42         fail.insert(s);
43         return false;
44     }
45 };
46 
47 //②动规-优化方法
48 class Solution {
49 public:
50     set<string> fail;
51     bool HeadOf(string A, string B){
52         if(A.length()>B.length()) return false;
53         for(int i=0;i<A.length();++i){
54             if(A[i]!=B[i]) return false;
55         }
56         return true;
57     }
58     bool wordBreak(string s, vector<string>& wordDict) {
59         auto p=fail.find(s);
60         if(p!=fail.end()) return false;
61         if(s=="") return true;
62         sort(wordDict.begin(), wordDict.end());
63         int wlen=wordDict.size(), slen=s.length();
64         if(wlen==0){
65             fail.insert(s);
66             return false;
67         }
68         int r=0, l=wlen-1, maxloc=-1;
69         while(l-r>1){
70             if( wordDict.at( (r+l)/2 )[0] < s[0]) r=(r+l)/2;
71             else l=(r+l)/2;
72         }
73         for(int i=r;i<wlen;++i){
74             if(wordDict.at(i)[0]==s[0]) maxloc=i;
75         }
76         if(maxloc==-1){
77             fail.insert(s);
78             return false;
79         }
80         for(int i=maxloc;i>=r;i--){
81             if(wordDict.at(i)[0]==s[0] && HeadOf(wordDict.at(i),s) ){
82                 string tmp;
83                 tmp.assign(s,wordDict.at(i).length(),slen-wordDict.at(i).length());
84                 if(wordBreak(tmp,wordDict)) return true;
85             }
86         }
87         fail.insert(s);
88         return false;
89     }
90 };
View Code
复制代码

!且慢——刚刚参考了dalao的代码,发现动规也被我做复杂了orz。可以从另一面考虑,用dp[i]==true/false记录原始待匹配单词的前i个字符是否恰好能被字典词匹配上,这样不用递归都行。另外,dalao还对其代码做了进一步优化,即找到字典中单词的最大长度maxWordLength,在循环计算时,对前i个单词的分割就可以从i-maxWordLength开始,如果这个数<0,就从0开始。

神奇版代码:

复制代码
 1 bool wordBreak(string s, vector<string>& wordDict) {
 2     vector<bool> dp(s.size()+1, false);
 3     unordered_set<string> m(wordDict.begin(), wordDict.end());
 4     dp[0] = true;
 5     //获取最长字符串长度
 6     int maxWordLength = 0;
 7     for (int i = 0; i < wordDict.size(); ++i){
 8         maxWordLength = std::max(maxWordLength, (int)wordDict[i].size());
 9     }
10     for (int i = 1; i <= s.size(); ++i){
11         for (int j = std::max(i-maxWordLength, 0); j < i; ++j){
12             if (dp[j] && m.find(s.substr(j, i-j)) != m.end()){
13                 dp[i] = true;
14                 break;
15             }
16         }
17     }
18     return dp[s.size()];
19 }
View Code
复制代码

 后记:以上三种方法的速度差异还是蛮大的,分别是48ms--16ms--0ms,orz……

6.26

【手感-链表操作】移除重复节点-力扣

  两种思路,①使用额外内存,用set储存到目前为止出现过的元素,一次遍历,删除出现过的节点;②不使用额外内存,两个指针逐个遍历每个未删除的节点。简单题,只写了第二种方法。

参考代码:

复制代码
 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode* removeDuplicateNodes(ListNode* head) {
12         ListNode* p1=head;
13         ListNode* p2=head;
14         if(p1==NULL) return head;
15         while((*p1).next!=NULL){
16             if(p2==NULL || (*p2).next==NULL){
17                 p1=(*p1).next;
18                 p2=p1;
19             }
20             else if( (*(*p2).next).val==(*p1).val ){
21                 (*p2).next= (*(*p2).next).next;
22             }
23             else{
24                 p2=(*p2).next;
25             }
26         }
27         return head;
28     }
29 };
View Code
复制代码

 6.27

【手感-链表操作】反转链表-力扣

  题不难,可以学习三种翻转方法。①三个指针交替翻转,其中一个是临时存储用的;②递归,如果当前节点或其下一个节点等于NULL,就直接返回当前节点。否则,新建一个res节点,保存下一层递归的返回值,下一层递归的参数的是当前头节点的下一个节点。在每一层中让当前节点的next节点的next指向自己,之后当前节点的next节点指向NULL,返回res节点;③神奇版双指针法。从头节点开始,向后遍历。把每个节点的next指向节点保存在头节点指针中,然后该节点的next指向前一个节点。这其中用两个指针保存即可(头节点充当了①方法中的第三个临时节点)。

参考代码(注:②③的思路和代码都是借鉴huwt的)

复制代码
 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 
10 //法①
11 class Solution {
12 public:
13     ListNode* reverseList(ListNode* head) {
14         if(head==NULL) return NULL;
15         if(head->next==NULL) return head;
16         ListNode* pre=NULL;
17         ListNode* cur=head;
18         ListNode* tmp=cur->next;
19         while(cur!=NULL){
20             tmp=cur->next;
21             cur->next=pre;
22             pre=cur;
23             cur=tmp;
24         }
25         return pre;
26     }
27 };
28 
29 //法②
30 class Solution {
31 public:
32     ListNode* reverseList(ListNode* head) {
33         if (head == NULL || head->next == NULL) {
34             return head;
35         }
36         ListNode* ret = reverseList(head->next);
37         head->next->next = head;
38         head->next = NULL;
39         return ret;
40     }
41 };
42 
43 //法③
44 class Solution {
45 public:
46     ListNode* reverseList(ListNode* head) {
47         if (head == NULL) { return NULL; }
48         ListNode* cur = head;
49         while (head->next != NULL) {
50             ListNode* t = head->next->next;
51             head->next->next = cur;
52             cur = head->next;
53             head->next = t;
54         }
55         return cur;
56     }
57 };
View Code
复制代码

 6.28

【思维】判断路径是否相交-力扣

  很有意思的题,难在思路,实现很简单,过目不忘。

参考代码:

复制代码
 1 //大佬解答,妙!
 2 class Solution {
 3 public:
 4     bool isPathCrossing(string path) {
 5         set<pair<int, int> > st;
 6         st.insert(make_pair(0, 0));
 7         int x = 0, y = 0;
 8         for(char c : path) {
 9             if(c == 'N') {
10                 x++;
11             }
12             else if(c == 'S') x--;
13             else if(c == 'E') y++;
14             else y--;
15             auto tmp = make_pair(x, y);
16             if(st.count(tmp)) return true;//每点状态唯一,储存状态到set,只需判断是否遇到过该状态
17             st.insert(tmp);
18         }
19         return false;
20     }
21 };
View Code
复制代码

【双指针】长度最小的子数组-力扣

  三种做法(为何没有一下看破!面壁去)。①极端的暴力循环法/前缀和暴力循环法;②前缀和+二分查找法;③双指针法。

  看到求“xx最小的子问题”的题就以为是动规,结果自己跳坑了。

参考代码:

复制代码
 1 //①自己用了前缀和暴力循环法过的
 2 class Solution {
 3 public:
 4     int minSubArrayLen(int s, vector<int>& nums) {
 5         int n=nums.size();
 6         vector<int> ori=nums;
 7         int sum[33200]={0};
 8         for(int i=0;i<n;++i){
 9             if(i>0) sum[i]=sum[i-1]+nums[i];
10             else sum[0]=nums[0];
11         }
12         sort(nums.begin(),nums.end());
13         int tmp=0, mmin=0, mmax=0;
14         for(int i=0;i<n;++i){
15             tmp+=nums[i];
16             if(tmp>=s){
17                 mmax=i+1;
18                 break;
19             }
20         }
21         tmp=0;
22         for(int i=n-1;i>=0;--i){
23             tmp+=nums[i];
24             if(tmp>=s){
25                 mmin=n-i;
26                 break;
27             }
28         }
29         if(mmin==mmax) return mmin;
30         for(int k=mmin;k<=mmax;++k){
31             for(int i=0;i<n;++i){
32                 if(i+k-1>=n) break;
33                 if(sum[i+k-1]-sum[i]+ori[i]>=s) return k;
34             }
35         }
36         return 0;
37     }
38 };
39 
40 //②前缀和+二分查找法
41 class Solution {
42 public:
43     int minSubArrayLen(int s, vector<int>& nums) {
44         int n = nums.size();
45         if (n == 0) {
46             return 0;
47         }
48         int ans = INT_MAX;
49         vector<int> sums(n + 1, 0); //可以动态指定vector长度
50         for (int i = 1; i <= n; i++) {
51             sums[i] = sums[i - 1] + nums[i - 1];
52         }
53         for (int i = 1; i <= n; i++) {
54             int target = s + sums[i - 1];
55             auto bound = lower_bound(sums.begin(), sums.end(), target);//啊别忘二分查找
56             if (bound != sums.end()) {
57                 ans = min(ans, static_cast<int>((bound - sums.begin()) - (i - 1)));
58             }
59         }
60         return ans == INT_MAX ? 0 : ans;
61     }
62 };
63 
64 //③双指针法
65 class Solution {//双指针法。一开始想到要用动规储存,但实际上不用储存,用双指针即可。
66 public:
67     int minSubArrayLen(int s, vector<int>& nums) {
68         int n = nums.size();
69         if (n == 0) {
70             return 0;
71         }
72         int ans = INT_MAX;
73         int start = 0, end = 0;
74         int sum = 0;
75         while (end < n) {
76             sum += nums[end];
77             while (sum >= s) {//满足条件就更新答案
78                 ans = min(ans, end - start + 1);
79                 sum -= nums[start];
80                 start++;
81             }
82             end++;//每次迭代end往右移
83         }
84         return ans == INT_MAX ? 0 : ans;
85     }
86 };
View Code
复制代码

 6.29

【思维-哈希表】罗马数字转整数-力扣

  有、意思的题,不要想复杂了。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int romanToInt(string s) {
 4         int len=s.length(), ans=0;
 5         int v[22]={0};//类似于哈希的存储方式
 6         v[(int)'I'-67]=1;
 7         v[(int)'V'-67]=5;
 8         v[(int)'X'-67]=10;
 9         v[(int)'L'-67]=50;
10         v[(int)'C'-67]=100;
11         v[(int)'D'-67]=500;
12         v[(int)'M'-67]=1000;
13         for(int i=0;i<len;++i){
14             if(i==len-1) ans+=v[(int)s[i]-67];
15             else{
16                 int a=v[(int)s[i]-67];
17                 int b=v[(int)s[i+1]-67];
18                 if(a<b){
19                     ans+=b-a;
20                     i++;
21                 }
22                 else ans+=a;
23             }
24         }
25         return ans;
26     }
27 };
View Code
复制代码

  此题的姊妹篇是 整数转罗马数字-力扣

虽然这两道题在LeetCode上分别被标为简单、中等难度,我私以为后一道题更容易通过找规律,只需求解一个“类”进制转换问题。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     string digit(int x, string one, string five, string ten){
 4         string d="";
 5         if(x<4){
 6             for(int i=0;i<x;++i){
 7                 d+=one;
 8             }
 9             return d;
10         }
11         else if(x==4) return one+five;
12         else if(x==9) return one+ten;
13         else{
14             d=five;
15             for(int i=0;i<x-5;++i){
16                 d+=one;
17             }
18             return d;
19         }
20         return "error";
21     }
22     string intToRoman(int num) {
23         string d1, d2, d3, d4;
24         d1=digit(num%10,"I","V","X");
25         num/=10;
26         d2=digit(num%10,"X","L","C");
27         num/=10;
28         d3=digit(num%10,"C","D","M");
29         num/=10;
30         d4=digit(num%10,"M","Error1","Error2");
31         return d4+d3+d2+d1;
32     }
33 };
View Code
复制代码

 6.30

【复习-STL】用两个栈实现队列-力扣

  程设作业似乎做过一道类似的,复习一下也好。

参考代码:

复制代码
 1 class CQueue {
 2 public:
 3     stack<int> pos;
 4     stack<int> rev;
 5     CQueue() {//栈的函数有push top pop
 6     }
 7     void appendTail(int value) {
 8         rev.push(value);
 9     }
10     int deleteHead() {
11         if(!pos.empty()){
12             int tmp=pos.top();
13             pos.pop();
14             return tmp;
15         }
16         while(!rev.empty()){
17             int tmp=rev.top();
18             pos.push(tmp);
19             rev.pop();
20         }
21         if(!pos.empty()){
22             int tmp=pos.top();
23             pos.pop();
24             return tmp;
25         }
26         return -1;
27     }
28 };
29 
30 /**
31  * Your CQueue object will be instantiated and called as such:
32  * CQueue* obj = new CQueue();
33  * obj->appendTail(value);
34  * int param_2 = obj->deleteHead();
35  */
View Code
复制代码

 7.1

【复习-动规】最长重复子数组-力扣

  这题与“最长公共子序列”有点相似,但暗含有连续数组的意思,某种程度上简化了状态转移方程。节省内存可以用一维数组,对数组剩下的那一维度逆序遍历,省略的维度顺序遍历即可。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int findLength(vector<int>& A, vector<int>& B) {
 4         int la=A.size();
 5         int lb=B.size();
 6         int dp[1100], ans=0;
 7 //dp[i][j]表示A的前i个元素形成的数组与B的前j个元素的数组的最长重复子数组个数,简化为一维dp[j]
 8         memset(dp,0,sizeof(dp));
 9         for(int i=1;i<=la;++i){
10             for(int j=lb;j>=1;--j){
11                 if(A[i-1]==B[j-1]) dp[j]=dp[j-1]+1;
12                 else dp[j]=0;
13                 ans=max(ans,dp[j]);//因为只有连续才有值,故答案是所有值中的最大者,而不是最后者
14             }
15         }
16         return ans;
17     }
18 };
View Code
复制代码

 7.2

【强行广搜】有序矩阵中第K小的元素-力扣

  一眼就能看出这是道排序题,且数据是部分有序的,正常做法是暴力排序、归并排序、二分查找。写题的时候傻了,居然每层循环sort了一次,生生给stl排序的时间复杂度乘了个n[扶额]……当时一拍脑袋,莫非这题不是在考排序查找?于是反手写了一个广搜,把元素从左上角依次加入优先队列,虽然慢点,但过了。有被自己的脑回路笑到,罢,就当复习广搜算了。

参考代码:

复制代码
 1 //正常暴力排序(其他复杂度较小的排序用别的题练吧,此题不写了)
 2 class Solution {
 3 public:
 4     int kthSmallest(vector<vector<int>>& matrix, int k) {
 5         int n=matrix.size();
 6         vector<int> my;
 7         for(int i=0;i<n;++i){
 8             for(int j=0;j<n;++j){
 9                 my.push_back(matrix[i][j]);
10             }
11         }
12         sort(my.begin(),my.end());
13         return my[k-1];
14     }
15 };
16 
17 //非常规做法—广搜
18 class Solution {
19 public:
20     struct Node{
21         int x, y, v;
22         Node(){}
23         Node(int i, int j, int vv):x(i),y(j),v(vv){}
24         bool operator < (Node b) const {
25             return v>b.v;//变成小顶堆
26         }
27     };
28     bool vis[300][300];
29     int kthSmallest(vector<vector<int>>& matrix, int k) {
30         int n=matrix.size(), cnt=0;
31         priority_queue<Node> my;
32         memset(vis, 0, sizeof(vis));
33         vis[0][0]=1;
34         my.push(Node(0,0,matrix[0][0]));
35         while(!my.empty()){
36             cnt++;
37             Node tmp=my.top();
38             if(cnt==k) return tmp.v;
39             int tx=tmp.x, ty=tmp.y;
40             my.pop();
41             if(tx+1<n && !vis[tx+1][ty]){
42                 my.push( Node(tx+1, ty, matrix[tx+1][ty]) );
43                 vis[tx+1][ty]=1;
44             }
45             if(ty+1<n && !vis[tx][ty+1]){
46                 my.push( Node(tx, ty+1, matrix[tx][ty+1]) );
47                 vis[tx][ty+1]=1;
48             }
49         }
50         return -1;
51     }
52 };
View Code
复制代码

 刚刚看到Sun君的优先队列解法很棒,mark一下。神奇版代码:

复制代码
 1 class Solution {
 2 public:
 3     int kthSmallest(vector<vector<int>>& matrix, int k) {
 4         priority_queue<int> pq;
 5         for (int i = 0; i < matrix.size(); ++i) {
 6             for (int j = 0; j < matrix[0].size(); ++j) {
 7                 pq.push(matrix[i][j]);
 8                 if (pq.size() > k) pq.pop();
 9             }
10         }
11         return pq.top();
12     }
13 };
View Code
复制代码

 7.3

今天事有点多,终于把小组分工定了[呼],明天补上!

7.4

【栈】有效的括号-力扣

  思路:A.倒序遍历,先找到最右边的左括号,再二次遍历其右边的紧邻是否匹配;B.遍历,对左括号入栈,遇到匹配的右括号就弹出栈顶元素;栈顶不匹配或未匹配完时栈已经为空,返回false。优化:长度为0直接返回true,长度为奇数直接返回false。

B思路的参考代码:

复制代码
 1 class Solution {
 2 public:
 3     bool isValid(string s) {
 4         int n=s.length();
 5         if(n%2) return false;
 6         if(!n) return true;
 7         stack<int> my;
 8         for(int i=0;i<n;++i){
 9             if(s[i]=='('|| s[i]=='['|| s[i]=='{') my.push(s[i]);
10             else{
11                 if(my.empty()) return false;
12                 int tmp=(int)s[i] +(int)my.top();
13                 if(tmp==81||tmp==184||tmp==248) my.pop();//为了简便损失了可读性,这里实际上就是判断栈顶元素是否是当前元素的左括号
14                 else return false;
15             }
16         }
17         if(!my.empty()) return false;
18         return true;
19     }
20 };
View Code
复制代码

 【动规】最长有效括号-力扣

   dalao的三种思路,太妙了!①动规,状态转移方程极妙;②栈,先入栈虚拟头元素-1;③正序逆序两次遍历,动态储存左右括号的数量与最新答案

动规思路的参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int dp[21000];//记录结尾是右括号的 前i个字符中最长有效括号位数
 4     int ans=0;
 5     int longestValidParentheses(string s) {
 6         int n=s.length();
 7         if(n==0) return 0;
 8         memset(dp,0,sizeof(dp));
 9         if(s[0]=='(' && s[1]==')') dp[1]=2;
10         for(int i=2;i<n;++i){
11             if(s[i]=='(') continue;//结尾是左括号的直接=0,实际上也阻断了前面连续有效括号对后面计数的影响,这个0值起到了分隔的作用
12             if(s[i-1]=='(') dp[i]=dp[i-2]+2;//最右边恰好是一对括号
13             else if(i-1-dp[i-1]>=0 && s[i-1-dp[i-1]]=='('){//最右边是两个右括号,向前找靠右侧的右括号对应的左括号,能找到则分几段计数(理解重点)
14                 dp[i]=dp[i-1]+2;
15                 if(i-2-dp[i-1]>=0) dp[i]+=dp[i-2-dp[i-1]];
16             }
17         }
18         for(int i=0;i<n;++i){
19             ans=max(ans,dp[i]);
20         }
21         return ans;
22     }
23 };
View Code
复制代码

 【递归回溯】括号生成-力扣

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     vector<string> my;
 4     int Max=-1;//设一个全局变量记录需要的最大左(右)括号数
 5     void gen(string s, int k, int l, int r){//k是剩余递归层数,l和r分别记录当前左右括号个数。基本原则是在每层递归,Max>=左括号数>=右括号数
 6         if(k==0){
 7             my.push_back(s);
 8             return;
 9         }
10         if(l==r){
11             gen(s+"(", k-1, l+1, r);
12         }
13         else{
14             if(l<Max) gen(s+"(", k-1, l+1, r);
15             gen(s+")", k-1, l, r+1);
16         }
17         return;
18     }
19     vector<string> generateParenthesis(int n) {
20         Max=n;
21         gen("", 2*n, 0, 0);
22         return my;
23     }
24 };
View Code
复制代码

 7.5

【匹配】通配符匹配-力扣

  这题写的真心心累……13次提交终于通过,真的是面向测试样例编程了hhh 歇够了再去看dalao更好的题解。

  自己的两种思路:①递归/去除连续的 '*' 之后的递归,对具体字母和 '?' 匹配一个字符,不匹配return false,对 '*' 递归匹配。但这两种写法都会超时;

  ②对模式串中的具体字符块搜索匹配。先忽略模式串中的'*',对字母和?搜索最近的匹配,不能匹配的/匹配串未匹配完的return false。但对特殊情况的处理超级麻烦,列举几个特殊情况:a.模式串尾部有*,但匹配串未匹配完,不能返回false;b.模式串头部无*,其余部分都能匹配上,但匹配串头部有未匹配部分,要返回false……另外,要非常小心访问越界。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int myRuntime=0;//用来记录是否是第一个匹配块,处理模式串头部无*,匹配串头部未匹配的特殊情况
 4     int myfind(int from, string ss, string pp){
 5         myRuntime++;
 6         int lst_loc=-1, lss=ss.length();
 7         for(int i=from;i<lss;++i){
 8             for(int j=0;j<pp.length();++j){
 9                 if(i+j>=lss) return -1;
10                 if(ss[i+j]!=pp[j] && pp[j]!='?') break;
11                 if(j==pp.length()-1){
12                     lst_loc=i+j;
13                     return lst_loc;
14                 }
15             }
16         }
17         return -1;
18     }
19     bool isMatch(string s, string p) {
20         int ls=s.length(), lp=p.length();
21         if(ls==0){
22             for(int i=0;i<lp;++i){
23                 if(p[i]!='*') return false;
24             }
25             return true;
26         }
27         if(lp==0) return false;
28         int ptr=0, lstres=0;
29         string ptmp="";
30         for(int i=0;i<lp;++i){
31             while(p[i]!='*' && i<lp){
32                 ptmp+=p.substr(i,1);
33                 i++;
34             }
35             if(ptmp!=""){
36                 int itmp=myfind(ptr, s, ptmp);
37                 if(myRuntime==1 && p[0]!='*' && itmp+1-ptmp.length()!=0) return false;
38                 if(itmp==-1) return false;
39                 else ptr=itmp+1;
40             }
41             ptmp="";
42         }
43         if(ptr!=ls && p[lp-1]!='*'){
44             string ptmp2="";
45             int lpp=ptmp2.length(), i2=0;
46             for(i2=lp-1;i2>=0;--i2){
47                 if(p[i2]=='*') break;
48                 while(i2>=0 && p[i2]!='*'){
49                     ptmp2=p.substr(i2,1)+ptmp2;
50                     i2--;
51                 }
52                 if(i2<0 || p[i2]=='*') break;
53             }
54             lpp=ptmp2.length();
55             for(int j=0;j<lpp;++j){
56                 if(ls-1-j<0 || s[ls-1-j]!=ptmp2[lpp-1-j] && ptmp2[lpp-1-j]!='?') return false;
57             }
58             if(i2<0 || p[i2]!='*') return false;
59         }
60         return true;
61     }
62 };
View Code
复制代码

 7.6

 7.7

 7.8

【动规-水题】三步问题-力扣

  优化存储空间!

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int waysToStep(int n) {
 4         int a=1, b=2, c=4, ans=a+b+c;
 5         if(n<3) return n;
 6         if(n==3) return 4;
 7         n=n-3;
 8         while(n--){
 9             ans=((a+b)%1000000007+c)%1000000007;
10             a=b;
11             b=c;
12             c=ans;
13         }
14         return ans;
15     }
16 };
View Code
复制代码

 7.9

【动规】恢复空格-力扣

  ①动规的思路比较常规,关键是剪枝:1.判断有效的单词长度(直接用set存储所有效的长度即可,也可以再加长度上下界的判断);2.已为0的dp[i]直接continue

  ②另一种思路是“字典树”,稍后整理。

参考代码:

复制代码
 1 //法1:动规,根据有效的单词长度进行状态转移
 2 class Solution {
 3 public:
 4     int min_res[1000];//对前下标<=k的k个字符形成的串断句,能达到的最小未识别字符数
 5     int sml=2000, big=0;
 6     int min(int a, int b){
 7         if(a<=b) return a;
 8         return b;
 9     }
10     int max(int a, int b){
11         if(a>=b) return a;
12         return b;
13     }
14     int respace(vector<string>& dictionary, string sentence) {
15         int slen=sentence.length(), dlen=dictionary.size();
16         if(dlen==0 || slen==0) return slen;
17         set<string> newdic;
18         set<int> mylen;
19         for(string str : dictionary){
20             newdic.insert(str);
21             mylen.insert(str.length());
22         }
23         for(int i=0;i<dlen;++i){
24             sml=min(sml,dictionary[i].length());
25             big=max(big,dictionary[i].length());
26             newdic.insert(dictionary[i]);
27         }
28         for(int k=0;k<slen;++k){
29             string tmp;
30             tmp.assign(sentence, 0, k+1);
31             if(newdic.find(tmp)!=newdic.end()) min_res[k]=0;
32             else min_res[k]=k+1;
33             for(int i=sml;i<=k && i<=big;++i){
34                 if(mylen.find(i)==mylen.end()) continue;
35                 tmp.assign(sentence, k-i+1, i);
36                 if(newdic.find(tmp)!=newdic.end()) min_res[k]=min(min_res[k], min_res[k-i]);
37             }
38             for(int i=1;;++i){
39                 if(k-i<0) break;
40                 if(i>=min_res[k]-min_res[k-i]) break;
41                 min_res[k]=min(min_res[k], min_res[k-i]+i);
42             }
43         }
44         return min_res[slen-1];
45     }
46 };
View Code
复制代码

……(这几天都有做题,参加了两场周赛,有点疲于总结了,不好不好。赶快补上啊)

 7.13

【二叉树】重建二叉树-力扣

  复习二叉树构建和遍历的好题。①自己的方法,额外开了内存进行递归,慢且笨拙;②dalao的方法-自己复刻了一遍,巧用STL的find函数,用指针传参也很有魅力hhh

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 //法①
11 class Solution {
12 public:
13     TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
14         int n=preorder.size();
15         TreeNode* root= new TreeNode;
16         root->right=new TreeNode;
17         root->left =new TreeNode;
18         if(n<=1){
19             if(n==0) root=NULL;
20             else{
21                 root->val=preorder[0];
22                 root->right=NULL;
23                 root->left=NULL;
24             }
25             return root;
26         }
27         root->val=preorder[0];
28         vector<int> pretmp1;
29         vector<int> pretmp2;
30         vector<int> intmp1;
31         vector<int> intmp2;
32         bool find=false;
33         for(int i=0;i<n;++i){
34             if(inorder[i]==preorder[0]){
35                 find=true;
36                 if(i>0) pretmp1.push_back(preorder[i]);
37             }
38             else if(!find){
39                 if(i>0) pretmp1.push_back(preorder[i]);
40                 intmp1.push_back(inorder[i]);
41             }
42             else{
43                 pretmp2.push_back(preorder[i]);
44                 intmp2.push_back(inorder[i]);
45             }
46         }
47         root->left =buildTree(pretmp1, intmp1);
48         root->right=buildTree(pretmp2, intmp2);
49         return root;
50     }
51 };
52 
53 //法②
54 /*
55 *注:学习了TheoWu的做法,自己重写的
56 *链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/cjian-dan-shi-xian-di-gui-by-theowu/
57 */
58 class Solution {
59 public:
60     TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
61         return Build(preorder.begin(),preorder.end(),inorder.begin(),inorder.end());
62     }
63     TreeNode* Build(vector<int>::iterator pre_s, vector<int>::iterator pre_e, vector<int>::iterator in_s, vector<int>::iterator in_e){
64         if(pre_s==pre_e) return NULL;
65         TreeNode* cur=new TreeNode(*pre_s);
66         auto root=find(in_s, in_e, *pre_s);
67         cur->left =Build(pre_s+1, pre_s+1+(root-in_s), in_s, root);
68         cur->right=Build(pre_s+1+(root-in_s), pre_e, root+1, in_e);
69         return cur;  
70     }
71 };
View Code
复制代码

 7.14

【位运算复习】二进制中1的个数-力扣

  水题,练手感……今天没做难题,在找实习了555

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int hammingWeight(uint32_t n) {
 4         int cnt=0;
 5         for(int i=0;i<=31;++i){
 6             if(n&(1<<i)) cnt++;
 7         }
 8         return cnt;
 9     }
10 };
View Code
复制代码

 7.15

【动规-二叉搜索树】不同的二叉搜索树-力扣

  初步解锁二叉搜索树!此题递归方法的思路自己想出来了,可以引申学习一下卡塔兰数。

参考代码:

复制代码
 1 /*
 2 二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树) 
 3 它或者是一棵空树,或者是具有下列性质的二叉树: 
 4 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 
 5 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 
 6 它的左、右子树也分别为二叉查找树。
 7 */
 8 //法① 动规
 9 class Solution {
10 public:
11     int Max=0;
12     int dp[1000];
13     int f(int k){
14         if(dp[k]>0 || k==0) return dp[k];
15         dp[k]=f(k-1)*2;
16         for(int i=1;i<=k-1;++i){
17             dp[k]+=f(k-i-1)*f(i);
18         }
19         return dp[k];
20     }
21     int numTrees(int n) {
22         memset(dp,0,sizeof(dp));
23         dp[1]=1;
24         dp[2]=2;
25         dp[3]=5;
26         Max=n;
27         return f(n);
28     }
29 };
30 
31 //法② 卡塔兰数计算(力扣提供)
32 
33 class Solution {
34 public:
35     int numTrees(int n) {
36         long long C = 1;
37         for (int i = 0; i < n; ++i) {
38             C = C * 2 * (2 * i + 1) / (i + 2);
39         }
40         return (int)C;
41     }
42 };
View Code
复制代码

 7.16

【深搜】判断二分图-力扣

  啊我解锁二分图了!顺带学了点并查集的概念(好机智啊这种数据结构)。此题的两种思路是①深搜/广搜;②并查集。

  匈牙利算法(判断是否图里还有交错的路径)

参考代码:

复制代码
 1 //深搜C++代码
 2 class Solution {
 3 public:
 4     bool vis[1000];
 5     int col[1000];
 6     int n;
 7     bool ans=true;
 8     void dfs(int k, int c, vector<vector<int>>& graph){
 9         if(!ans) return;
10         if(graph[k].size()==0) return;
11         for(int j=0;j<graph[k].size();++j){
12             int i=graph[k][j];
13             if(i==k) continue;
14             if(vis[i]==1){
15                 if(col[i]==1-c) continue;
16                 ans=false;
17                 return;
18             }
19             vis[i]=1;
20             col[i]=1-c;
21             dfs(i, 1-c, graph);
22         }
23         return;
24     }
25     bool isBipartite(vector<vector<int>>& graph) {
26         memset(vis, 0, sizeof(vis));
27         memset(col, -1, sizeof(col));
28         n=graph.size();
29         for(int i=0;i<n;++i){
30             for(int j=0;j<graph[i].size();++j){
31                 if(vis[graph[i][j]]) continue;
32                 dfs(graph[i][j], 0, graph);
33             }
34         }
35         return ans;
36     }
37 };
View Code
复制代码
复制代码
 1 //dalao的Java代码,下次补上自己的C++/Python代码
 2 class Solution {
 3     public boolean isBipartite(int[][] graph) {
 4         // 初始化并查集
 5         UnionFind uf = new UnionFind(graph.length);
 6         // 遍历每个顶点,将当前顶点的所有邻接点进行合并
 7         for (int i = 0; i < graph.length; i++) {
 8             int[] adjs = graph[i];
 9             for (int w: adjs) {
10                 // 若某个邻接点与当前顶点已经在一个集合中了,说明不是二分图,返回 false。
11                 if (uf.isConnected(i, w)) {
12                     return false;
13                 }
14                 uf.union(adjs[0], w);
15             }
16         }
17         return true;
18     }
19 }
20 
21 // 并查集
22 class UnionFind {
23     int[] roots;
24     public UnionFind(int n) {
25         roots = new int[n]; 
26         for (int i = 0; i < n; i++) {
27             roots[i] = i;
28         }
29     }
30 
31     public int find(int i) {
32         if (roots[i] == i) {
33             return i;
34         }
35         return roots[i] = find(roots[i]);
36     }
37 
38     // 判断 p 和 q 是否在同一个集合中
39     public boolean isConnected(int p, int q) {
40         return find(q) == find(p);
41     }
42 
43     // 合并 p 和 q 到一个集合中
44     public void union(int p, int q) {
45         roots[find(p)] = find(q);
46     }
47 }
View Code
复制代码

 7.17

【复习-二分】第一个错误的版本-力扣

  等hr(!后来发现是老板)开完会打面试电话ing……刷会题好了。这道题的测试点比较强,所以二分的条件一定要卡好,另外注意一下大整数相加除以2防止溢出的问题

参考代码:

复制代码
 1 // The API isBadVersion is defined for you.
 2 // bool isBadVersion(int version);
 3 
 4 class Solution {
 5 public:
 6     int firstBadVersion(int n) {
 7         int l=0, r=n, m;
 8         while(l<r){
 9             m=l/2+r/2+1;
10             if(isBadVersion(m)) r=m-1;
11             else l=m;
12         }
13         if(isBadVersion(l)) return l;
14         return l+1;
15     }
16 };
View Code
复制代码

7.18

7.19

7.20

7.21

7.22

【二分】旋转数组的最小值-力扣

  这几天有收到好消息诶。加油!此题是为了考二分而考二分,不许偷偷排序。总体思路是,被“简单洗牌”的数据,前半部分一定大于等于后半部分。

  值得注意的点是,重复元素会非常干扰二分查找边界,可以在遇到时先去重,或对区间再二分搜索判断。

参考代码:

复制代码
 1 //没有去重,对重复点的区间查找
 2 class Solution {//类似于简单洗牌
 3 public:
 4     int minArray(vector<int>& numbers) {
 5         int n=numbers.size();
 6         int s=numbers[0], l=0, r=n-1;
 7         while(r-l>2){
 8             int t=l/2+r/2;
 9             if(numbers[t]<s) r=t;
10             else if(numbers[t]>s) l=t;
11             else{//重复!查找该点到结尾是否为包含答案的区间,注意1个ans+(N-1)个x的特殊情况
12                 int p=t;
13                 while(numbers[p]==s){
14                     p++;
15                     if(p==n-1){
16                         if(numbers[n-1]==s) r=t-1;
17                         else l=t+1;
18                         break;
19                     }
20                 }
21                 if(p!=n-1) l=t+1;
22             }
23         }
24         for(int i=l-3;i<=l+3;++i){
25             if(i<0||i>=n) continue;
26             if(numbers[i]<s) return numbers[i];
27         }
28         return s;
29     }
30 }
View Code
复制代码

 8.11

【二叉树】二叉树的层序遍历-力扣

  今天开始要尽快做完二叉树tag!

  这道题看了提示做出来的,多开一个变量num记录下一层放入的节点个数,每次在队列里处理前num个节点。

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     vector<vector<int> > levelOrder(TreeNode* root) {
13         vector<vector<int> > ans;
14         if(!root) return ans;
15 
16         queue<TreeNode*> q;
17         q.push(root);
18         int num=1;
19 
20         while(!q.empty()){
21             int ntmp=0;
22             vector<int> vtmp;
23             for(int i=0;i<num;++i){
24                 TreeNode* k=q.front();
25                 q.pop();
26                 vtmp.push_back(k->val);
27                 if(k->left){
28                     q.push(k->left);
29                     ntmp++;
30                 }
31                 if(k->right){
32                     q.push(k->right);
33                     ntmp++;                    
34                 }
35             }
36             ans.push_back(vtmp);
37             num=ntmp;
38         }
39 
40         return ans;
41     }
42 };
View Code
复制代码

 8.12

【深搜/图】克隆图-力扣

  这道题迫使人用哈希表标记访问过的点,因此创建了一个unordered_map<Node*, Node*>,还蛮有意思的一题。刚开始没做出来,看了解答后自己又敲了三遍代码↓

参考代码:

复制代码
 1 /*
 2 // Definition for a Node.
 3 class Node {
 4 public:
 5     int val;
 6     vector<Node*> neighbors;
 7     
 8     Node() {
 9         val = 0;
10         neighbors = vector<Node*>();
11     }
12     
13     Node(int _val) {
14         val = _val;
15         neighbors = vector<Node*>();
16     }
17     
18     Node(int _val, vector<Node*> _neighbors) {
19         val = _val;
20         neighbors = _neighbors;
21     }
22 };
23 */
24 
25 class Solution {
26 public:
27     unordered_map<Node*, Node*> vis;
28     Node* cloneGraph(Node* node) {
29         if(!node) return NULL;
30         if(vis.find(node)!= vis.end()) return vis[node];//先返回这种情况会比较快
31 
32         Node* Cnode = new Node(node->val);//别忘了new
33         vis[node] = Cnode;//!!
34 
35         for(auto x = node->neighbors.begin(); x!=node->neighbors.end(); ++x){
36             Cnode->neighbors.push_back(cloneGraph(*x));
37         }
38         return Cnode;
39     }
40 };
View Code
复制代码

 8.13——今天是左撇子日喔!祝左撇子朋友们节日快乐啊[跳跳]

【字符串】字符串相乘-力扣

  复习大整数乘法。注:对两个大整数,每两位直接相乘,先将整数存储到答案数组对应的位置上、再逐位进制会较快,另外要多预留首一位,在不需要进一位时通过判断去掉。

参考代码:

复制代码
 1 class Solution {
 2 public:
 3     string Int2String(int x){
 4         string s = "?";
 5         s[0] = '0'+x;
 6         return s;
 7     }
 8     string multiply(string num1, string num2) {
 9         if (num1 == "0" || num2 == "0") {
10             return "0";
11         }
12         int m = num1.size(), n = num2.size();
13         vector<int> ansArr( m+n, 0 );//声明vector时预设长度的一种方法,长度为m+n,值均为0(0可以换成其他值)
14         for(int i = m - 1; i >= 0; --i){
15             for(int j = n - 1; j >= 0; --j){
16                 ansArr[i+j+1] += (num1[i]-'0') * (num2[j]-'0');
17             }
18         }
19         for(int i = n + m - 1; i > 0; --i){
20             ansArr[i - 1] += ansArr[i]/10;
21             ansArr[i] %= 10;
22         }        
23     int p = 0;
24     string ans = "";
25     if (ansArr[0]==0) p+=1;
26     while(p < n+m){
27         ans = ans + Int2String(ansArr[p]);
28         p++;
29     }
30     return ans;
31     }
32 };
View Code
复制代码

 【二叉树】填充每个节点的下一个右侧节点指针 II-力扣

  题目要求用常数空间O(1)解答,使用的栈空间不计。故不能用广搜/队列(为啥我用了就超时了555),可以用递归。此题的关键是找到next节点,使用bro临时节点在函数中保存并传参。next指针本身就带有方向,所以和队列存储的原理是一致的。

参考代码:

复制代码
 1 /*
 2 // Definition for a Node.
 3 class Node {
 4 public:
 5     int val;
 6     Node* left;
 7     Node* right;
 8     Node* next;
 9 
10     Node() : val(0), left(NULL), right(NULL), next(NULL) {}
11     Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {}
12     Node(int _val, Node* _left, Node* _right, Node* _next)
13         : val(_val), left(_left), right(_right), next(_next) {}
14 };
15 */
16 
17 class Solution {
18 public:
19     void Run(Node* root, Node* cousin){
20         if(!root) return;
21         Node* bro = cousin;//临时变量bro用来记录和root子节点同一层(即root的下一层)的右边最靠近的节点
22         if(root->right){
23             while(bro!=NULL){//while循环的意义是往右走,往下走,直到找到下一层第一个节点
24                 if(bro->left){
25                     bro = bro->left;
26                     break;
27                 }
28                 if(bro->right){
29                     bro = bro->right;
30                     break;
31                 }
32                 bro = bro->next;
33             }
34             (root->right)->next = bro;
35             if(root->left) (root->left)->next = (root->right);
36             Run(root->right, bro);
37             Run(root->left, root->right);
38         }
39         else if(root->left){
40             while(bro!=NULL){
41                 if(bro->left){
42                     bro = bro->left;
43                     break;
44                 }
45                 if(bro->right){
46                     bro = bro->right;
47                     break;
48                 }
49                 bro = bro->next;
50             }
51             if(root->right){
52                 (root->right)->next = bro;
53                 (root->left)->next = (root->right);                
54             }
55             else{
56                 (root->left)->next = bro;
57             }
58             Run(root->left, (root->left)->next);
59             Run(root->right, bro);
60         }
61         return ;
62     }
63     Node* connect(Node* root) {
64         Run(root, NULL);
65         return root;
66     }
67 };
View Code
复制代码

 【二叉树】二叉树的最近公共祖先-力扣

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
13         if(!root || root == p || root == q) return root;
14         TreeNode* l = lowestCommonAncestor(root->left, p, q);
15         TreeNode* r = lowestCommonAncestor(root->right, p, q);
16         //当l和r都不为NULL时,只有一种可能,说明p, q与root直接相连,在其左右两侧,应返回root;
17         //l和r不可能都为NULL(跟丢了p和q)
18         //故,当r、l其中一个为NULL,应返回另一个值
19         if(!l) return r;
20         if(!r) return l;
21         return root;
22     }
23 };
View Code
复制代码

 【二叉树】二叉树的序列化与反序列化-力扣

  这题也太难了呜呜……下次应该先看看题目难度再做。参考了forgetthing大佬的代码,又加了点注释↓

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Codec {
11 public:
12 
13     // Encodes a tree to a single string.
14     string serialize(TreeNode* root) {
15         string res;
16         dfs_s(root, res);
17         return res;
18     }
19 
20     // 前序遍历序列转化为字符串               //注:在字符串中加null和空格,就只需要一种遍历方式
21     void dfs_s(TreeNode* root, string& res) {
22         if (!root) {
23             res += "null ";
24             return;
25         }
26         res += to_string(root->val) + ' ';
27         dfs_s(root->left, res);
28         dfs_s(root->right, res);
29     }
30 
31     // Decodes your encoded data to tree.
32     TreeNode* deserialize(string data) {
33         // 开始遍历索引
34         int u = 0;
35         return dfs_d(data, u);
36     }
37 
38     TreeNode* dfs_d(string& data, int& u) { //还要考虑多位整数的计算
39         if (u >= data.size()) return NULL;
40         if (data[u] == 'n') {
41             u = u + 5;
42             return NULL;
43         }
44         int val = 0, sign = 1;
45         if (data[u] == '-') sign = -1, u ++ ;
46         while(data[u] != ' '){val = val * 10 + data[u] - '0'; u++;}
47         val *= sign;
48         u = u + 1 ;
49 
50         auto root = new TreeNode(val);
51         root->left = dfs_d(data, u);
52         root->right = dfs_d(data, u);
53 
54         return root;
55     }
56 };
57 
58 // Your Codec object will be instantiated and called as such:
59 // Codec codec;
60 // codec.deserialize(codec.serialize(root));
View Code
复制代码

 8.14

  今天也非常特殊,因为今天力扣的每日一题终于是一道做过的题了,而且今天进入新的tag啦,开启"二叉搜索树"!以后会有越来越多的题被做过啊

【二叉搜索树】验证二叉搜索树-力扣

  这道题算是二叉搜索树入门级的练习,注意整数的边界一定要取满,是2147483648(1<<31)和-2147483648

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     bool judge(TreeNode* root, int up, int down, int upValid, int downValid){
13         if(!root) return true;
14         int ov = root->val;
15         if(root->left){
16             int lv = root->left->val;
17             if( lv >= ov || (downValid && lv <= down) || (upValid && lv >= up) ) return false;
18             if(!judge(root->left, min(ov, up), down, true, downValid) ) return false;
19         }
20         if(root->right){
21             int rv = root->right->val;
22             if( rv <= ov || (downValid && rv <= down) || (upValid && rv >= up) ) return false;
23             if(!judge(root->right, up, max(ov, down), upValid, true) ) return false;
24         }
25         return true;
26     }
27     bool isValidBST(TreeNode* root) {
28         if(!root) return true;
29         return judge(root, 2147483647, -2147483648, false, false);
30     }
31 };
View Code
复制代码

 【二叉搜索树】二叉搜索树迭代器-力扣

  这题不难,主要考中序遍历。AC后看别人的题解,一大半都是用栈模拟,用vector的人好少hhh

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class BSTIterator {
11 public:
12     vector<int> vals;
13     int p;
14     int len;
15     BSTIterator(TreeNode* root){
16         Inorder(root);
17         p = 0;
18         len = vals.size();
19     }
20     void Inorder(TreeNode* root){
21         if(!root) return;
22         if(root->left){
23             Inorder(root->left);
24         }
25         vals.push_back(root->val);
26         if(root->right){
27             Inorder(root->right);
28         }
29         return;
30     }
31     /** @return the next smallest number */
32     int next() {
33         return vals[p++];
34     }
35     
36     /** @return whether we have a next smallest number */
37     bool hasNext() {
38         return p < len;
39     }
40 };
41 
42 /**
43  * Your BSTIterator object will be instantiated and called as such:
44  * BSTIterator* obj = new BSTIterator(root);
45  * int param_1 = obj->next();
46  * bool param_2 = obj->hasNext();
47  */
View Code
复制代码

 8.17

【二叉树】平衡二叉树-力扣

  优化递归效率:自顶而下=>自底而上

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 
11 //法一:自顶而下
12 class Solution {
13 public:
14     void cal(TreeNode* rt, int depth, int& ans){
15         if(!rt) return;
16         if( !(rt->left) && !(rt->right)){
17             ans = max(ans, depth);
18             return;
19         }
20         if(rt->left) cal(rt->left, depth+1, ans);
21         if(rt->right) cal(rt->right, depth+1, ans);
22         return;
23     }
24     int maxDepth(TreeNode* root) {
25         int ans = 0;
26         if(!root) return 0;
27         cal(root, 1, ans);
28         return ans;
29     }
30     bool isBalanced(TreeNode* root) {
31         if(!root) return true;
32         int t = maxDepth(root->left) - maxDepth(root->right);
33         if(t<-1 || t>1) return false;
34         if(!isBalanced(root->left)) return false;
35         if(!isBalanced(root->right)) return false;
36         return true;
37     }
38 };
39 
40 //法二:自底而上
41 class Solution {
42 public:
43     int cal_h(TreeNode* root){
44         if(!root) return 0;
45         int rh = cal_h(root->right);
46         int lh = cal_h(root->left);
47         if(rh == -1 || lh == -1 || abs(rh-lh)>1 ) return -1; //返回值非常巧妙!
48         return max(1+rh, 1+lh);
49     }
50     bool isBalanced(TreeNode* root) {
51         return cal_h(root)>=0;
52     }
53 };
View Code
复制代码

 【二叉树】删除二叉搜索树中的节点-力扣

  这题还真是有那么点意思。分三种情况,①删除叶子节点,直接删;②存在右子树(也就存在中序后继节点),用中序后继节点的值赋值(或交换,注意一下后面待删除节点的值),然后在右子树中递归删除中序后继节点;③存在左子树(也就存在中序前缀节点),用中序前缀节点的值赋值,然后在左子树中递归删除中序前缀节点

  另外,卡住半天的地方是递归删除时,参数应该传root的左(右)子树的根节点,并把返回值赋给左(右)子树的根节点。

参考代码:

复制代码
 1 /**
 2  * Definition for a binary tree node.
 3  * struct TreeNode {
 4  *     int val;
 5  *     TreeNode *left;
 6  *     TreeNode *right;
 7  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 8  * };
 9  */
10 class Solution {
11 public:
12     TreeNode* findPre(TreeNode* root){//找中序前缀节点
13         root = root->left;
14         while(root->right){
15             root = root->right;
16         }
17         return root;
18     }
19     TreeNode* findNext(TreeNode* root){//找到中序后继节点
20         root = root->right;
21         while(root->left){
22             root = root->left;
23         }
24         return root;
25     }
26     TreeNode* deleteNode(TreeNode* root, int key) {
27         if(!root) return NULL;
28         if(root->val == key){
29             if(!root->left && !root->right){//要删除的是叶子节点
30                 root = NULL;
31                 return root;
32             }
33             else if(root->right){//要删除的节点存在右孩子,用后继节点的值补充
34             //右子树向下递归删除该后继节点,后继节点一定没有右孩子
35             TreeNode* tmp = findNext(root);
36                 root->val = tmp->val;
37                 root->right = deleteNode(root->right, tmp->val);
38                 return root;
39             }
40             else if(root->left){//要删除的节点存在左孩子,用前缀节点的值补充
41             //左子树向下递归删除该前缀节点,前缀节点一定没有左孩子
42             TreeNode* tmp = findPre(root);
43                 root->val = tmp->val;
44                 root->left = deleteNode(root->left, tmp->val);
45                 return root;
46             }
47         }
48         else if(root->val < key){
49             root->right = deleteNode(root->right, key);
50             return root;
51         }
52         else{
53             root->left = deleteNode(root->left, key);
54             return root;
55         }
56         return root;
57     }
58 };
View Code
复制代码

 8.18

【二叉树】有序链表转换二叉树-力扣

  这道题与二叉平衡树的构造密切相关,注意构造的方式不唯一。用类似于二分的方法构造平衡二叉树,其合理性和效率可以得到证明

参考代码:

复制代码
 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 /**
12  * Definition for a binary tree node.
13  * struct TreeNode {
14  *     int val;
15  *     TreeNode *left;
16  *     TreeNode *right;
17  *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
18  *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
19  *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
20  * };
21  */
22 class Solution {
23 public:
24     TreeNode* helper(vector<int>& nums, int left, int right) {
25         if (left > right) {
26             return nullptr;
27         }
28         // 总是选择中间位置左边的数字作为根节点
29         int mid = (left + right) / 2;
30         TreeNode* root = new TreeNode(nums[mid]);
31         root->left = helper(nums, left, mid - 1);
32         root->right = helper(nums, mid + 1, right);
33         return root;
34     }
35     TreeNode* sortedListToBST(ListNode* head) {
36         vector<int> nums;
37         while(head){
38             nums.push_back(head->val);
39             head = head->next;
40         }
41         return helper(nums, 0, nums.size() - 1);
42     }
43 };
View Code
复制代码

 8.21

【二叉树】数据流中的第K大元素-力扣

  第一次用二叉搜索树的形式完成这种题hh,耗时还真是……一言难尽啊。贴一下自己和大佬YouLookDeliciousC 的代码,大佬在构建树时就已经开始计数了,更快,没有对比没有伤害诶

参考代码:

复制代码
  1 /**
  2  * Your KthLargest object will be instantiated and called as such:
  3  * KthLargest* obj = new KthLargest(k, nums);
  4  * int param_1 = obj->add(val);
  5  */
  6 
  7 //1.自己的代码,很笨拙,为了处理特殊情况不得不增加全局变量
  8 class KthLargest {
  9 public:
 10     class MyTree{
 11         public:
 12             int val;
 13             MyTree* left = NULL;
 14             MyTree* right = NULL;
 15             MyTree(int x):val(x){}
 16             MyTree(){}
 17     };
 18     MyTree* build(MyTree* root, vector<int>& nums, int s, int e){
 19         if(s>=e) return NULL;
 20         int t = (e+s)/2;
 21         if(root==NULL){
 22             root = new MyTree(nums[t]);
 23         }
 24         else root->val = nums[t];
 25         root->left = build(root->left, nums, s, t);
 26         root->right = build(root->right, nums, t+1, e);
 27         return root;
 28     }
 29 
 30     int cnt = 0, ans = -1, key = -1, len = -1;
 31     MyTree* Myroot = new MyTree(-1);
 32     bool empty = true;
 33 
 34     void help(MyTree* root, int val){
 35         if(!root){
 36             root = new MyTree(val);
 37             return;
 38         }
 39         if(root->val < val){
 40             if(!root->right){
 41                 root->right = new MyTree(val);
 42                 return;
 43             }
 44             help(root->right, val);
 45             return;
 46         }
 47         else{
 48             if(!root->left){
 49                 root->left = new MyTree(val);
 50                 return;
 51             }
 52             help(root->left, val);
 53             return;
 54         }
 55         return;
 56     }
 57 
 58     void Scan(MyTree* s){
 59         if(!s) return;
 60         Scan(s->right);
 61         cnt++;
 62         if(cnt == key){
 63             ans = s->val;
 64             return;
 65         }
 66         else if (cnt>key){
 67             return;
 68         }
 69         Scan(s->left);
 70         return;
 71     }
 72 
 73     KthLargest(int k, vector<int>& nums) {
 74         key = k;
 75         len = nums.size();
 76         if(len>0) empty = false;
 77         sort(nums.begin(), nums.end());
 78         Myroot = build(Myroot, nums, 0, len );
 79     }
 80     
 81     int add(int val) {
 82         cnt = 0;
 83         ans = -1;
 84         if(empty){
 85             Myroot = new MyTree(val);
 86             empty = false;
 87         }
 88         else help(Myroot, val);
 89         Scan(Myroot);
 90         return ans;
 91     }
 92 };
 93 
 94 //2.大佬的代码,简洁!
 95 class KthLargest {
 96     struct TreeNode{
 97         int val;
 98         int count; // 用以记录以包括当前节点,左右子树在内。有多少个节点。
 99         TreeNode* left;
100         TreeNode* right;
101         TreeNode(int x): val(x), left(NULL), right(NULL), count(1) {}
102     };
103 public:
104 
105     int K;
106     TreeNode* root;
107     TreeNode* addNode(TreeNode* root, int val){ // 构建二叉搜索树
108         if(!root)   return new TreeNode(val);
109         if(val <= root -> val){ //如果子树的点加一,该节点的count值加一
110             root -> count += 1;
111             root -> left = addNode(root -> left, val);
112         }else{
113             root -> count += 1;
114             root -> right = addNode(root -> right, val);
115         }
116         return root;
117     }
118     int findNum(TreeNode* treeRoot, int k){
119         int m = 1;
120         if(treeRoot -> right)   m = treeRoot -> right -> count + 1; //m是root加上右子树的所有节点的数量
121         if(k == m)  return treeRoot -> val;
122         if(k < m) { // 右子树的节点大于k,目标点在右子树
123             return findNum(treeRoot -> right, k);
124         }
125         else{
126             return findNum(treeRoot -> left, k - m); //右子树的节点加上根节点小于k个,目标点在左子树
127         }
128     }
129 
130 
131     KthLargest(int k, vector<int>& nums): K(k), root(NULL) {
132         for(auto i : nums){ //创建二叉搜索树
133             root = addNode(root, i);
134         }
135     }
136     
137     int add(int val) {
138         root = addNode(root, val); //更新子树
139         return findNum(root, K);
140     }
141 };
View Code
复制代码

 9.16

【二分法&快慢指针】寻找重复数-力扣

  挺神奇的一道题,在限制了大小为n+1的数组中只含有1~n的数后,有很多解法。挑两种总结一下下:

①二分法(有点强行二分的意思)

  “我们定义cnt[i] 表示nums[] 数组中小于等于 i 的数有多少个,假设我们重复的数是 target,那么[1,target−1]里的所有数满足 cnt[i]≤i,[target,n] 里的所有数满足cnt[i]>i,具有单调性。” ——力扣

②快慢指针(Floyd 判圈算法)

  此方法真的惊艳。使用条件为,图中存在环。

  操作:

  “我们先设置慢指针slow 和快指针 fast ,慢指针每次走一步,快指针每次走两步,根据「Floyd 判圈算法」两个指针在有环的情况下一定会相遇,此时我们再将slow 放置起点 0,两个指针每次同时移动一步,相遇的点就是答案。”  ——力扣

  原理:

  “假设环长为 L,从起点到环的入口的步数是 a,从环的入口继续走 b 步到达相遇位置,从相遇位置继续走 c 步回到环的入口,则有 b+c=L,其中 L、a、b、c 都是正整数。根据上述定义,慢指针走了 a+b 步,快指针走了 2(a+b) 步。从另一个角度考虑,在相遇位置,快指针比慢指针多走了若干圈,因此快指针走的步数还可以表示成 a+b+kL,其中 k 表示快指针在环上走的圈数。联立等式,可以得到

2(a+b)=a+b+kL

解得 a=kL−b,整理可得

a=(k-1)L+(L-b)=(k-1)L+c

从上述等式可知,如果慢指针从起点出发,快指针从相遇位置出发,每次两个指针都移动一步,则慢指针走了 a 步之后到达环的入口,快指针在环里走了 k−1 圈之后又走了 c 步,由于从相遇位置继续走 c 步即可回到环的入口,因此快指针也到达环的入口。两个指针在环的入口相遇,相遇点就是答案。”

——力扣

快慢指针法参考代码:

复制代码
 1 class Solution {
 2 public:
 3     int findDuplicate(vector<int>& nums) {
 4         int slow = 0, fast = 0;
 5         do {
 6             slow = nums[slow];
 7             fast = nums[nums[fast]];
 8         } while (slow != fast);
 9         slow = 0;
10         while (slow != fast) {
11             slow = nums[slow];
12             fast = nums[fast];
13         }
14         return slow;
15     }
16 };
View Code
复制代码

-------------1个月100道题的flag倒了,抽空继续完成。现在在准备几天后基于HackerRank的1h笔试网测-------------------- 

9.26

【数组&排序】New Year Chaos -HackerRank

  容易超时,需要精确优化。自己的两种思路,仅供参考:①逆序对的数量就是答案,但是用两层循环计数、一半测试点会超时;②原题可看做“冒泡打乱”,就用冒泡排序还原,记录交换位置的次数。注意要不断优化冒泡排序的区间。

参考代码:

复制代码
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 vector<string> split_string(string);
 4 
 5 // Complete the minimumBribes function below.//只需完成此函数代码
 6 void minimumBribes(vector<int> q){
 7     int ans = 0, len = q.size();
 8     vector<int> pre(len, 0);
 9     for(int i = 0; i < len; ++i){
10         if(q[i] - (i+1) > 2){
11             cout<<"Too chaotic"<<endl;
12             return;
13         }
14     }
15     int s = 0, e = len - 1;
16     while(s<e){
17         while(s < e && q[s] == s+1){
18             s++;
19         }
20         if(s >= e) break;
21         for(int i = s; i < e; ++i){
22             if(q[i] > q[i+1]){
23                 ans += 1;
24                 swap(q[i], q[i+1]);
25             }
26         }
27     }
28     cout<<ans<<endl;
29     return;
30 }
31 
32 int main()
33 {
34     int t;
35     cin >> t;
36     cin.ignore(numeric_limits<streamsize>::max(), '\n');
37 
38     for (int t_itr = 0; t_itr < t; t_itr++) {
39         int n;
40         cin >> n;
41         cin.ignore(numeric_limits<streamsize>::max(), '\n');
42 
43         string q_temp_temp;
44         getline(cin, q_temp_temp);
45 
46         vector<string> q_temp = split_string(q_temp_temp);
47 
48         vector<int> q(n);
49 
50         for (int i = 0; i < n; i++) {
51             int q_item = stoi(q_temp[i]);
52 
53             q[i] = q_item;
54         }
55 
56         minimumBribes(q);
57     }
58 
59     return 0;
60 }
61 
62 vector<string> split_string(string input_string) {
63     string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
64         return x == y and x == ' ';
65     });
66 
67     input_string.erase(new_end, input_string.end());
68 
69     while (input_string[input_string.length() - 1] == ' ') {
70         input_string.pop_back();
71     }
72 
73     vector<string> splits;
74     char delimiter = ' ';
75 
76     size_t i = 0;
77     size_t pos = input_string.find(delimiter);
78 
79     while (pos != string::npos) {
80         splits.push_back(input_string.substr(i, pos - i));
81 
82         i = pos + 1;
83         pos = input_string.find(delimiter, i);
84     }
85 
86     splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));
87 
88     return splits;
89 }
View Code
复制代码

 

posted on   Mju_halcyon  阅读(170)  评论(0编辑  收藏  举报

编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示