zoukankan      html  css  js  c++  java
  • LeetCode OJ 题解

    博客搬至blog.csgrandeur.com,cnblogs不再更新。

    新的题解会更新在新博客http://blog.csgrandeur.com/3/

    ————————————————————————————————————————

    ————————————————————————————————————————

    LeetCode OJ 题解

    LeetCode OJ is a platform for preparing technical coding interviews.

    LeetCode OJ 是为与写代码有关的技术工作面试者设计的训练平台。

    LeetCode OJ:http://oj.leetcode.com/

    默认题目顺序为题目添加时间倒叙,本文题解顺序与OJ题目顺序一致(OJ会更新,至少目前一致。。。),目前共152题。

    Made By:CSGrandeur

    另外,Vimer做了Python版的题解:http://c4fun.cn/blog/2014/03/20/leetcode-solution-02/

    ————————————————————————————————————————

    Maximum Product Subarray

     维护当前位置连续乘积的最大值 tmpp 和最小值 tmpn ,最大值和最小值都可能由三种情况得到:上一个数的 tmpp*A[i],上一个数的 tmpn*A[i],A[i]本身。

    不断更新答案,最终输出。

     1 class Solution {
     2 public:
     3     int maxProduct(int A[], int n) {
     4         int tmpp = A[0], tmpn = A[0], tmp, ans = A[0];
     5         for(int i = 1; i < n; i ++)
     6         {
     7             tmp = tmpp;
     8             tmpp = max(max(A[i], A[i] * tmpp), A[i] * tmpn);
     9             tmpn = min(min(A[i], A[i] * tmp), A[i] * tmpn);
    10             ans = max(ans, tmpp);
    11         }
    12         return ans;
    13     }
    14 };
    View Code

    Reverse Words in a String

     先翻转整个字符串,然后从前往后一个单词一个单词地再翻转一次,同时去除多余空格,等于是扫描两遍,O(n)。

     1 class Solution {
     2 public:
     3     void reverseWords(string &s) {
     4         reverse(s.begin(), s.end());
     5         int start = 0, end = 0, j = 0;
     6         while(start != s.length())
     7         {
     8             while(start != s.length() && s[start] == ' ') start ++;
     9             for(end = start; end != s.length() && s[end] != ' '; end ++);
    10             if(j != 0 && start <= end - 1) s[j ++] = ' ';
    11             for(int i = end - 1; start < i; start ++, i --)
    12                 swap(s[i], s[start]), s[j ++] = s[start];
    13             while(start < end) s[j ++] = s[start ++];
    14         }
    15         s.resize(j);
    16     }
    17 };
    View Code

    Evaluate Reverse Polish Notation

    逆波兰表达式计算四则运算。用栈。

     1 class Solution {
     2 public:
     3     int evalRPN(vector<string> &tokens) {
     4         int a, b;
     5         stack<int> s;
     6         for(int i = 0; i < tokens.size(); i ++)
     7         {
     8             if(isdigit(tokens[i][0]) || tokens[i].length() > 1)
     9             {
    10                 s.push(atoi(tokens[i].c_str()));
    11                 continue;
    12             }
    13             a = s.top();s.pop();
    14             b = s.top();s.pop();
    15             switch(tokens[i][0])
    16             {
    17                 case '+': s.push(b + a); break;
    18                 case '-': s.push(b - a); break;
    19                 case '*': s.push(b * a); break;
    20                 case '/': s.push(b / a); break;
    21             }
    22         }
    23         return s.top();
    24     }
    25 };
    View Code

    Max Points on a Line

     平面上一条直线最多穿过多少点。乍一看好熟悉的问题,做了这么久计算几何。。。却还真没做过这个小问题。

    第一反应当然不能O(n^3)枚举了,枚举圆周好像也不行,毕竟是考察所有点,不是某个点。那么应该就是哈希斜率了吧。

    肯定少不了竖直的线,哈希斜率这不像是这类OJ让写的题吧。。忘了map这回事了。

    确定思路之后,还是看看别人博客吧,少走点弯路,然后就学习了还有unordered_map这么个东西,还有一个博客的思路挺好,避免double问题,把斜率转化成化简的x、y组成字符串。

    再另外就是重叠的点了,想让题目坑一点,怎能少得了这种数据,单独处理一下。

     1 /**
     2  * Definition for a point.
     3  * struct Point {
     4  *     int x;
     5  *     int y;
     6  *     Point() : x(0), y(0) {}
     7  *     Point(int a, int b) : x(a), y(b) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     int maxPoints(vector<Point> &points) {
    13         int ans = 0;
    14         for(int i = 0; i < points.size(); i ++)
    15         {
    16             unordered_map<string, int> mp;
    17             int tmpans = 0, same = 0;
    18             for(int j = i + 1; j < points.size(); j ++)
    19             {
    20                 int x = points[j].x - points[i].x, y = points[j].y - points[i].y;
    21                 int g = gcd(x, y);
    22                 if(g != 0) x /= g, y /= g;
    23                 else {same ++; continue;}
    24                 if(x < 0) x = -x, y = -y;
    25                 string tmp = to_string(x) + " " + to_string(y);
    26                 if(!mp.count(tmp)) mp[tmp] = 1;
    27                 else mp[tmp] ++;
    28                 tmpans = max(tmpans, mp[tmp]);
    29             }
    30             ans = max(tmpans + 1 + same, ans);
    31         }
    32         return ans;
    33     }
    34     int gcd(int a, int b)
    35     {
    36         return a ? gcd(b % a, a) : b;
    37     }
    38 };
    View Code

    Sort List

     又长见识了,原来链表也可以O(nlogn)排序的。没往下想就查了一下,看到人说用归并,于是才开始想能不能实现。。。

    O(n)找到中点,把中点的next变成NULL,对两部分递归。递归结束后对两部分归并,先找到newhead,即两部分的头部val较小的那个,然后归并就把小的从newhead往后续。

    把最后的next赋值NULL,返回newhead。

    又有空数据@_@.

     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 *sortList(ListNode *head) {
    12         int n = 0;
    13         ListNode *p = head;
    14         while(p != NULL)
    15             n ++, p = p->next;
    16         if(n <= 1) return head;
    17         n >>= 1;
    18         p = head;
    19         while(-- n)
    20             p = p->next;
    21         ListNode *tmp = p->next;
    22         p->next = NULL;
    23         ListNode *nl = sortList(head);
    24         ListNode *nr = sortList(tmp);
    25         ListNode *newhead;
    26         if(nl->val < nr->val)
    27         {
    28             newhead = nl;
    29             nl = nl->next;
    30         }
    31         else
    32         {
    33             newhead = nr;
    34             nr = nr->next;
    35         }
    36         p = newhead;
    37         while(nl != NULL && nr != NULL)
    38         {
    39             if(nl->val < nr->val) p->next = nl, p = p->next, nl = nl->next;
    40             else p->next = nr, p = p->next, nr = nr->next;
    41         }
    42         while(nl != NULL) p->next = nl, p = p->next, nl = nl->next;
    43         while(nr != NULL) p->next = nr, p = p->next, nr = nr->next;
    44         p->next = NULL;
    45         return newhead;
    46     }
    47 };
    View Code

    Insertion Sort List

     指针操作很烦啊。。暴力枚举插入位置,注意细节就能过了。

     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 *insertionSortList(ListNode *head) {
    12         ListNode *newhead = head;
    13         if(head == NULL) return NULL;
    14         head = head->next;
    15         newhead->next = NULL;
    16         while(head != NULL)
    17         {
    18             if(head->val < newhead->val)
    19             {
    20                 ListNode *tmp = head->next;
    21                 head->next = newhead;
    22                 newhead = head;
    23                 head = tmp;
    24                 continue;
    25             }
    26             ListNode *pre = newhead, *p = newhead->next;
    27             while(p != NULL && p->val < head->val)
    28             {
    29                 p = p->next;
    30                 pre = pre->next;
    31             }
    32             pre->next = head;
    33             head = head->next;
    34             pre = pre->next;
    35             pre->next = p;
    36         }
    37         return newhead;
    38     }
    39     
    40 };
    View Code

    LRU Cache

    新建数据类class Val,保存key、val和访问自增标记updatecnt。

    用unordered_map更新数据,增加updatecnt,并把更新的数据放入队列,最关键是处理capacity满了的时候,队列依次出队,map中不存在的和updatecnt和最新数据不相等的项目都忽略,直到发现updatecnt和map中存的最新状态相等,则为“最近未使用”数据,出队后在map中erase。思路有点像STL队列实现版本的Dijkstra。

    有一个博客的方法更好,map中存的是链表的节点指针,链表顺序表示访问情况,这样就把map内容和链表的每个节点一一对应了,没有冗余节点,且更新操作也是O(1)的。

     1 class Val{
     2 public:
     3     int key;
     4     int val;
     5     int updatecnt;
     6 };
     7 class LRUCache{
     8 public:
     9     int cap;
    10     unordered_map<int, Val> mp;
    11     queue<Val> q;
    12     LRUCache(int capacity) {
    13         cap = capacity;
    14     }
    15 
    16     int get(int key) {
    17         if(mp.count(key))
    18         {
    19             mp[key].updatecnt ++;
    20             q.push(mp[key]);
    21             return mp[key].val;
    22         }
    23         return -1;
    24     }
    25 
    26     void set(int key, int value) {
    27         if(mp.count(key))
    28         {
    29             mp[key].val = value;
    30             mp[key].updatecnt ++;
    31             q.push(mp[key]);
    32         }
    33         else
    34         {
    35             if(mp.size() == cap)
    36             {
    37                 Val tmp;
    38                 while(!q.empty())
    39                 {
    40                     tmp = q.front();
    41                     q.pop();
    42                     if(mp.count(tmp.key) && tmp.updatecnt == mp[tmp.key].updatecnt)
    43                         break;
    44                 }
    45                 mp.erase(mp.find(tmp.key));
    46                 mp[key].key = key;
    47                 mp[key].val = value;
    48                 mp[key].updatecnt = 0;
    49                 q.push(mp[key]);
    50             }
    51             mp[key].key = key;
    52             mp[key].val = value;
    53             mp[key].updatecnt = 0;
    54             q.push(mp[key]);
    55         }
    56     }
    57 };
    View Code

    Binary Tree Postorder Traversal

     二叉树的非递归后序遍历,考研的时候非常熟悉了,现在写又要想好久。重点是关于右子树遍历时候需要一个标记,或者标记根节点出栈次数,或者标记右子树是否访问。

     1 /**
     2  * Definition for binary tree
     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<int> postorderTraversal(TreeNode *root) {
    13         vector<int> ans;
    14         if(root == NULL) return ans;
    15         stack<TreeNode*> s;
    16         TreeNode *visited;
    17         while(root != NULL || !s.empty())
    18         {
    19             while(root != NULL)
    20                 s.push(root), root = root->left;
    21             root = s.top();
    22             if(root->right == NULL || visited == root->right)
    23             {
    24                 ans.push_back(root->val);
    25                 s.pop();
    26                 visited = root;
    27                 root = NULL;
    28             }
    29             else
    30             {
    31                 root = root->right;
    32             }
    33         }
    34         return ans;
    35     }
    36 };
    View Code

    Binary Tree Preorder Traversal

     前序遍历的非递归就容易多了。

     1 /**
     2  * Definition for binary tree
     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<int> preorderTraversal(TreeNode *root) {
    13         stack<TreeNode*> s;
    14         vector<int> ans;
    15         if(root == NULL) return ans;
    16         s.push(root);
    17         while(!s.empty())
    18         {
    19             root = s.top();
    20             s.pop();
    21             ans.push_back(root->val);
    22             if(root->right != NULL) s.push(root->right);
    23             if(root->left != NULL) s.push(root->left);
    24         }
    25     }
    26 };
    View Code

      

    Reorder List

    找到中间位置,把中间之后的链表反转,两个指针一个从头一个从尾开始互插,奇偶和指针绕得有点晕,理清就好了。。

     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     void reorderList(ListNode *head) {
    12         int n = 0;
    13         ListNode *pre, *p = head;
    14         while(p)
    15             n ++, p = p->next;
    16         if(n < 3) return;
    17         n >>= 1;
    18         pre = p = head;
    19         p = p->next;
    20         while(n --) p = p->next, pre = pre->next;
    21         while(p != NULL) 
    22         {
    23             ListNode *tmp = p->next;
    24             p->next = pre;
    25             pre = p;
    26             p = tmp;
    27         }
    28         ListNode *tail = pre;
    29         p = head;
    30         while(true)
    31         {
    32             ListNode *tmp1 = p->next, *tmp2 = tail->next;
    33             p->next = tail;
    34             tail->next = tmp1;
    35             p = tmp1;
    36             if(p == tail || p == tmp2) break;
    37             tail = tmp2;
    38         }
    39         p->next = NULL;
    40     }
    41 };
    View Code

    Linked List Cycle II

    设置两个指针slow和fast,从head开始,slow一次一步,fast一次两步,如果fast能再次追上slow则有圈。

    设slow走了n步,则fast走了2*n步,设圈长度m,圈起点到head距离为k,相遇位置距离圈起点为t,则有:

    n = k + t + pm; (1)

    2*n = k + t + qm;(2)

    这里p和q是任意整数。(不过fast速度是slow二倍,则肯定在一圈内追上,p就是0了)

    2 * (1) - (2) 得k = lm - t;(l = q - 2 * p)

     即 k 的长度是若干圈少了 t 的长度。

    因此这时候,一个指针从head开始,另一个从相遇位置开始,都每次只走一步,当从head开始的指针走到圈开始位置时,两指针刚好相遇。

     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 *detectCycle(ListNode *head) {
    12         if(head == NULL) return NULL;
    13         ListNode *slow, *fast;
    14         slow = fast = head;
    15         int n = 0;
    16         do
    17         {
    18             n ++;
    19             if(slow == NULL || fast == NULL) return NULL;
    20             slow = slow->next;
    21             fast = fast->next;
    22             if(fast == NULL) return NULL;
    23             fast = fast->next;
    24             if(fast == NULL) return NULL;
    25         }while(slow != fast);
    26         fast = head;
    27         while(slow != fast)
    28             slow = slow->next, fast = fast->next;
    29         return fast;
    30     }
    31 };
    View Code

    Linked List Cycle

     呃,时间逆序做的结果。。。成买一送一了。

     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     bool hasCycle(ListNode *head) {
    12         if(head == NULL) return false;
    13         ListNode *slow, *fast;
    14         slow = fast = head;
    15         int n = 0;
    16         do
    17         {
    18             n ++;
    19             if(slow == NULL || fast == NULL) return NULL;
    20             slow = slow->next;
    21             fast = fast->next;
    22             if(fast == NULL) return NULL;
    23             fast = fast->next;
    24             if(fast == NULL) return NULL;
    25         }while(slow != fast);
    26         return true;
    27     }
    28 };
    View Code

    Word Break II

     先递推,dp[i] == true 表示 s 中前 i 个字符的串是符合要求的,枚举位置 i ,对于 i 枚举位置 j < i,如果 dp[j] == true且 j ~ i的串在字典中,则dp[i] = true。

    同时对于这样的 j, i,site[i].push_back(j),即在 i 位置的可行迭代表中增加位置 j。

    完成site之后,从尾部倒着DFS过去就得到了所有串。

     1 class Solution {
     2 public:
     3     vector<string> DFS(const string &s, vector<int> *site, int ith)
     4     {
     5         vector<string> res;
     6         for(int i = 0; i < site[ith].size(); i ++)
     7         {
     8             vector<string> tmp;
     9             string str = s.substr(site[ith][i], ith - site[ith][i]);
    10             if(site[site[ith][i]].size() == 0)
    11                 res.push_back(str);
    12             else
    13             {
    14                 tmp = DFS(s, site, site[ith][i]);
    15                 for(int j = 0; j < tmp.size(); j ++)
    16                     res.push_back(tmp[j] + " " + str);
    17             }
    18         }
    19         return res;
    20     }
    21     vector<string> wordBreak(string s, unordered_set<string> &dict) {
    22         vector<int> *site = new vector<int>[s.length() + 1];
    23         bool *dp = new bool[s.length() + 1];
    24         memset(dp, 0, sizeof(bool) * s.length());
    25         dp[0] = true;
    26         for(int i = 1; i <= s.length(); i ++)
    27         {
    28             for(int j = 0; j < i; j ++)
    29             {
    30                 if(dp[j] == true && dict.count(s.substr(j, i - j)))
    31                    site[i].push_back(j), dp[i] = true;
    32             }
    33         }
    34         return DFS(s, site, s.length());
    35     }
    36 };
    View Code

    Word Break

     参考Word Break II,对于dp标记,当dp[i]为true时候可以停止枚举后面的 j,优化一下常数。

     1 class Solution {
     2 public:
     3     bool wordBreak(string s, unordered_set<string> &dict) {
     4         bool *dp = new bool[s.length() + 1];
     5         memset(dp, 0, sizeof(bool) * (s.length() + 1));
     6         dp[0] = true;
     7         for(int i = 1; i <= s.length(); i ++)
     8             for(int j = 0; j < i; j ++)
     9             {
    10                 dp[i] = dp[i] || dp[j] && dict.count(s.substr(j, i - j));
    11             }
    12             return dp[s.length()];
    13     }
    14 };
    View Code

    Copy List with Random Pointer

    第一次遍历,把每个节点复制一份放到对应节点的下一个,即组成二倍长的链表:ori1->copy1->ori2->copy2->....

    第二次遍历,利用“复制节点总是对应节点的下一个节点”特性,将每个ori->next->random指向ori->random->next,中间判断一下空指针。

    第三次遍历,把两个链表拆开,恢复原链表。

     1 /**
     2  * Definition for singly-linked list with a random pointer.
     3  * struct RandomListNode {
     4  *     int label;
     5  *     RandomListNode *next, *random;
     6  *     RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     RandomListNode *copyRandomList(RandomListNode *head) {
    12         RandomListNode *p = head, *newhead = NULL, *tmp;
    13         if(p == NULL) return NULL;
    14         while(p != NULL)
    15         {
    16             tmp = new RandomListNode(p->label);
    17             tmp->next = p->next;
    18             p->next = tmp;
    19             p = tmp->next;
    20         }
    21         newhead = head->next;
    22         p = head;
    23         while(p != NULL)
    24         {
    25             tmp = p->next;
    26             tmp->random = p->random == NULL ? NULL : p->random->next;
    27             p = tmp->next;
    28         }
    29         p = head;
    30         while(p != NULL)
    31         {
    32             tmp = p->next;
    33             p->next = tmp->next;
    34             p = tmp->next;
    35             tmp->next = p == NULL ? NULL : p->next;
    36         }
    37         return newhead;
    38     }
    39 };
    View Code

    Single Number II

    方法一:设置cnt[32]记录 32个比特位的1的个数,出现3次的数的对应位的1总数为3的倍数,则统计之后每个位对3取模,剩下的位为1的则对应个数为1的那个数。

     1 class Solution {
     2 public:
     3     int singleNumber(int A[], int n) {
     4         int cnt[32] = {0};
     5         for(int i = 0; i < n; i ++)
     6         {
     7             int tmp = A[i];
     8             for(int j = 0; j < 33; tmp >>= 1, j ++)
     9                 cnt[j] += tmp & 1;
    10         }
    11         int ans = 0;
    12         for(int i = 0; i < 32; i ++)
    13             ans |= (cnt[i] % 3) << i;
    14         return ans;
    15     }
    16 };
    View Code

    方法二:设置int one, two模拟两位二进制来统计各比特位1次数,每当one和two对应二进制位都为1的时候把one和two都清零,最后剩下的one就是要求的数。

     1 class Solution {
     2 public:
     3     int singleNumber(int A[], int n) {
     4         int one = 0, two = 0;
     5         for(int i = 0; i < n; i ++)
     6         {
     7             two |= one & A[i];
     8             one ^= A[i];
     9             int tmp = one & two;
    10             two ^= tmp;
    11             one ^= tmp;
    12         }
    13         return one;
    14     }
    15 };
    View Code

    Single Number

     一路异或过去就可以了。

    1 class Solution {
    2 public:
    3     int singleNumber(int A[], int n) {
    4         int tmp = 0;
    5         for(int i = 0; i < n; i ++)
    6             tmp ^= A[i];
    7         return tmp;
    8     }
    9 };
    View Code

    Candy

    时间复杂度 O(n)的方法还是容易想了,优化为空间复杂度O(1)的话也不难,只是思考代码的时候会有点绕。

    上坡一步步来,下坡走个等差数列,波峰位置比较一下上坡时候记录的最大值和下坡求的的最大值,取较大的,具体看代码:

     1 class Solution {
     2 public:
     3     int candy(vector<int> &ratings) {
     4         int cnt = 0, i, j, start, nownum;
     5         for(i = 0; i < ratings.size(); i ++)
     6         {
     7             if(i == 0 || ratings[i] == ratings[i - 1])
     8                 nownum = 1;
     9             else if(ratings[i] > ratings[i - 1])
    10                 nownum ++;
    11             if(i + 1 < ratings.size() && ratings[i + 1] < ratings[i])
    12             {
    13                 start = 1;
    14                 for(j = i + 1; j < ratings.size() && ratings[j] < ratings[j - 1]; start++, j ++);
    15                 if(start > nownum)
    16                     cnt += (start + 1) * start >> 1;
    17                 else
    18                     cnt += ((start - 1) * start >> 1) + nownum;
    19                 nownum = 1;
    20                 i = j - 1;
    21             }
    22             else 
    23                 cnt += nownum;
    24         }
    25         return cnt;
    26     }
    27 };
    View Code

    Gas Station

     证明题。

    一、如果从 i 到 j 的时候理论计算气量刚好为负数,则 i ~ j 的加气站都不可以作为起点。

    反证一下,从前往后去掉站,如果去掉的站能增加气,即正数,则结果更糟。如果去掉的站是负数,那么负数如果抵消了之前的正数,则在到 j 之前已经负数了,如果不能抵消之前的正数,那么结果还是更糟。

    二、判断是否能成行,一个环的和为非负就可以。

    假设环为正, 0 ~ j 刚好为负, j + 1 ~ k 刚好为负数,k + 1 之后为正,则 k + 1 为答案。

    也反证一下,k + 1 出发,到gas.size() - 1都为正,则转回来到 j - 1 都会为正。如果到 j 时候为负,则整个环不可能为正,所以到 j 的时候也为正,剩下的一样。这样就能够成功转一圈。

     1 class Solution {
     2 public:
     3     int canCompleteCircuit(vector<int> &gas, vector<int> &cost) {
     4        int i, ans, sum, all;
     5        for(i = ans = sum = all = 0; i < gas.size(); i ++)
     6        {
     7            sum += gas[i] - cost[i];
     8            all += gas[i] - cost[i];
     9            if(sum < 0)
    10            {
    11                sum = 0;
    12                ans = i + 1;
    13            }
    14        }
    15        return all >= 0 ? ans : -1;
    16     }
    17 };
    View Code

    Clone Graph

     label是唯一的,递归,用unordered_map标记。

     1 /**
     2  * Definition for undirected graph.
     3  * struct UndirectedGraphNode {
     4  *     int label;
     5  *     vector<UndirectedGraphNode *> neighbors;
     6  *     UndirectedGraphNode(int x) : label(x) {};
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     unordered_map<int, UndirectedGraphNode *> mp;
    12     UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
    13         if(node == NULL || mp.count(node->label)) return NULL;
    14         UndirectedGraphNode *tmp = new UndirectedGraphNode(node->label);
    15         mp[node->label] = tmp;
    16         for(int i = 0; i < node->neighbors.size(); i ++)
    17         {
    18             cloneGraph(node->neighbors[i]);
    19             tmp->neighbors.push_back(mp[node->neighbors[i]->label]);
    20         }
    21         return tmp;
    22     }
    23 };
    View Code

    Palindrome Partitioning II

    O(n^2)的动态规划。

    cutdp[i] 表示前 i 个字符最小切割几次。

    paldp[i][j] == true 表示 i ~ j 是回文。

    在枚举 i 和 i 之前的所有 j 的过程中就得到了 paldp[j][i] 的所有回文判断,而对于 i + 1,paldp[j][i + 1]可由 s[j]、s[i + 1]、dp[j + 1][i]在O(1)判断。

    cutdp[i]为所有 j (j < i),当paldp[j + 1][i] == true的 cutdp[j] + 1的最小值。注意一下边界。

     1 class Solution {
     2 public:
     3     int minCut(string s) {
     4         bool paldp[s.length()][s.length()];
     5         int cutdp[s.length()];
     6         for(int i = 0; i < s.length(); i ++)
     7         {
     8             cutdp[i] = 0x3f3f3f3f;
     9             for(int j = i - 1; j >= -1; j --)
    10             {
    11                 if(s.at(j + 1) == s.at(i) && (j + 2 >= i - 1 || paldp[j + 2][i - 1]))
    12                 {
    13                     paldp[j + 1][i] = true;
    14                     cutdp[i] = min(cutdp[i], (j >= 0 ? (cutdp[j] + 1) : 0));
    15                 }
    16                 else
    17                     paldp[j + 1][i] = false;
    18                     
    19             }
    20         }
    21         return cutdp[s.length() - 1];
    22     }
    23 };
    View Code

    Palindrome Partitioning

     O(n^2)动态规划,paldp[i][j]  == true表示 i ~ j 是回文。这里DP的方法是基本的,不再多说。

    得到paldp之后,DFS一下就可以了。因为单字符是回文,所以DFS的终点肯定都是解,所以不必利用其他的结构存储答案信息。

     1 class Solution {
     2 public:
     3     vector<vector<string> >res;
     4     vector<string> tmp;
     5     bool **paldp;
     6     void DFS(string s, int ith)
     7     {
     8         if(ith == s.length())
     9         {
    10             res.push_back(tmp);
    11             return;
    12         }
    13         for(int i = ith; i < s.length(); i ++)
    14         {
    15             if(paldp[ith][i])
    16             {
    17                 tmp.push_back(s.substr(ith, i - ith + 1));
    18                 DFS(s, i + 1);
    19                 tmp.pop_back();
    20             }
    21         }
    22         return;
    23     }
    24     vector<vector<string> > partition(string s) {
    25         paldp = new bool*[s.length()];
    26         for(int i = 0; i < s.length(); i ++)
    27             paldp[i] = new bool[s.length()];
    28         for(int i = 0; i < s.length(); i ++)
    29             for(int j = i; j >= 0; j --)
    30                 paldp[j][i] = s.at(i) == s.at(j) && (j + 1 >= i - 1 || paldp[j + 1][i - 1]);
    31         DFS(s, 0);
    32         return res;
    33     }
    34 };
    View Code

    Surrounded Regions

     周围四条边的O做起点搜索替换为第三种符号,再遍历所有符号把O换成X,第三种符号换回O。

     1 class Solution {
     2 public:
     3     typedef pair<int, int> pii;
     4     int dx[4] = {1, -1, 0, 0};
     5     int dy[4] = {0, 0, 1, -1};
     6     queue<pii> q;
     7     void solve(vector<vector<char> > &board) {
     8         if(board.size() == 0) return;
     9         int width = board[0].size();
    10         int height = board.size();
    11         for(int i = 0; i < width; i ++)
    12         {
    13             if(board[0][i] == 'O')
    14                 board[0][i] = '#', q.push(pair<int, int>(0, i));
    15             if(board[height - 1][i] == 'O')
    16                 board[height - 1][i] = '#', q.push(pii(height - 1, i));
    17         }
    18         for(int i = 1; i < height - 1; i ++)
    19         {
    20             if(board[i][0] == 'O')
    21                 board[i][0] = '#', q.push(pii(i, 0));
    22             if(board[i][width - 1] == 'O')
    23                 board[i][width - 1] = '#', q.push(pii(i, width - 1));
    24         }
    25         while(!q.empty())
    26         {
    27             pii now = q.front();
    28             q.pop();
    29             for(int i = 0; i < 4; i ++)
    30             {
    31                 int ty = now.first + dx[i];
    32                 int tx = now.second + dy[i];
    33                 if(tx >= 0 && tx < width && ty >= 0 && ty < height && board[ty][tx] == 'O')
    34                 {
    35                     board[ty][tx] = '#';
    36                     q.push(pii(ty, tx));
    37                 }
    38             }
    39         }
    40         for(int i = 0; i < height; i ++)
    41             for(int j = 0; j < width; j ++)
    42             {
    43                 if(board[i][j] == 'O') board[i][j] = 'X';
    44                 else if(board[i][j] == '#') board[i][j] = 'O';
    45             }
    46     }
    47 };
    View Code

    Sum Root to Leaf Numbers

     遍历一遍加起来。。。

     1 /**
     2  * Definition for binary tree
     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     int ans;
    13     void DFS(TreeNode *now, int tmp)
    14     {
    15         if(now->left == NULL && now->right == NULL)
    16         {
    17             ans += tmp * 10 + now->val;
    18             return;
    19         }
    20         if(now->left != NULL)
    21         {
    22             DFS(now->left, tmp * 10 + now->val);
    23         }
    24         if(now->right != NULL)
    25         {
    26             DFS(now->right, tmp * 10 + now->val);
    27         }
    28     }
    29     int sumNumbers(TreeNode *root) {
    30         if(root == NULL) return 0;
    31         ans = 0;
    32         DFS(root, 0);
    33         return ans;
    34     }
    35 };
    View Code

    Longest Consecutive Sequence

     方法一:一开始竟然想了并查集,其实绕弯了,多此一举。哈希+并查集,把每个数哈希,枚举每个数看相邻的数在不在数组里,并查集合并,只是并查集的复杂度要比O(1)大一些。

     1 class Solution {
     2 public:
     3     unordered_map<int, int> mp, cnt;
     4     int ans = 1;
     5     int fa(int i)
     6     {
     7         i == mp[i] ? i : (mp[i] = fa(mp[i]));
     8     }
     9     int longestConsecutive(vector<int> &num) {
    10         for(int i = 0; i < num.size(); i ++)
    11             mp[num[i]] = num[i], cnt[num[i]] = 1;
    12         for(int i = 0; i < num.size(); i ++)
    13         {
    14             if(mp.count(num[i] + 1) && fa(num[i]) != fa(num[i] + 1))
    15             {
    16                 cnt[fa(num[i] + 1)] += cnt[fa(num[i])];
    17                 ans = max(cnt[fa(num[i] + 1)], ans);
    18                 mp[fa(num[i])] = fa(num[i] + 1);
    19             }
    20         }
    21         return ans;
    22     }
    23 };
    View Code

    方法二:哈希+枚举相邻数。相邻的数在数组里的话,每个数之多访问一次;相邻的数不在数组里的话,枚举会中断。所以设哈希复杂度为O(1)的话,这个方法是严格的O(n)。

    其实这个题的数据挺善良,如果出了2147483647, -2147483648,那还是用long long 稳妥些。

     1 class Solution {
     2 public:
     3     unordered_map<int, bool> vis;
     4     int longestConsecutive(vector<int> &num) {
     5         int ans = 0;
     6         for(int i = 0; i < num.size(); i ++)
     7             vis[num[i]] = false;
     8         for(int i = 0; i < num.size(); i ++)
     9         {
    10             if(vis[num[i]] == false)
    11             {
    12                 int cnt = 0;
    13                 for(int j = num[i]; vis.count(j); j ++, cnt ++)
    14                 {
    15                     vis[j] = true;
    16                 }
    17                 for(int j = num[i] - 1; vis.count(j); j --, cnt ++)
    18                 {
    19                     vis[j] = true;
    20                 }
    21                 ans = max(ans, cnt);
    22             }
    23         }
    24         
    25         return ans;
    26     }
    27 };
    View Code

    Word Ladder II

     用数组类型的队列,BFS过程中记录pre路径,搜完后迭代回去保存路径。

    似乎卡了常数,用queue队列,另外存路径的方法超时了。

    想更快就双向广搜吧。让我想起了POJ那个八数码。

     1 class Node
     2 {
     3 public:
     4     string str;
     5     int pace;
     6     int pre;
     7     Node(){}
     8     Node(string s, int pa, int pr)
     9     {
    10         str = s;
    11         pace = pa;
    12         pre = pr;
    13     }
    14 };
    15 class Solution {
    16 public:
    17     vector<vector<string>> ans;
    18     vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
    19         vector<Node> q;
    20         q.push_back(Node(end, 1, -1));
    21         unordered_map<string, int> dis;
    22         dis[end] = 1;
    23         for(int i = 0; i < q.size(); i ++)
    24         {
    25             Node now = q[i];
    26             if(dis.count(start) && now.pace >= dis[start]) break;
    27             for(int j = 0; j < now.str.length(); j ++)
    28             {
    29                 string tmp = now.str;
    30                 for(char c = 'a'; c <= 'z'; c ++)
    31                 {
    32                     tmp[j] = c;
    33                     if((dict.count(tmp) || tmp == start) && (!dis.count(tmp) || dis[tmp] == now.pace + 1))
    34                     {
    35                         dis[tmp] = now.pace + 1;
    36                         q.push_back(Node(tmp, now.pace + 1, i));
    37                     }
    38                 }
    39             }
    40         }
    41         for(int i = q.size() - 1; i >= 0 && q[i].pace == dis[start]; i --)
    42         {
    43             if(q[i].str == start)
    44             {
    45                 vector<string> tmp;
    46                 for(int j = i; j != -1; j = q[j].pre)
    47                     tmp.push_back(q[j].str);
    48                 ans.push_back(tmp);
    49             }
    50         }
    51         return ans;
    52     }
    53 };
    View Code

    Word Ladder

     直接BFS。

     1 class Solution {
     2 public:
     3     int ladderLength(string start, string end, unordered_set<string> &dict) {
     4         typedef pair<string, int> pii;
     5         unordered_set<string> flag;
     6         queue<pii> q;
     7         q.push(pii(start, 1));
     8         while(!q.empty())
     9         {
    10             pii now = q.front();
    11             q.pop();
    12             for(int i = 0; i < now.first.length(); i ++)
    13             {
    14                 string tmp = now.first;
    15                 for(char j = 'a'; j <= 'z'; j ++)
    16                 {
    17                     tmp[i] = j;
    18                     if(tmp == end) return now.second + 1;
    19                     if(dict.count(tmp) && !flag.count(tmp))
    20                     {
    21                         q.push(pii(tmp, now.second + 1));
    22                         flag.insert(tmp);
    23                     }
    24                 }
    25             }
    26         }
    27         return 0;
    28     }
    29 };
    View Code

    Valid Palindrome

     做过刘汝佳 白书的人想必都知道ctype.h和isdigit(), isalpha, tolower(), toupper()。

     1 class Solution {
     2 public:
     3     bool valid(char &x)
     4     {
     5         x = tolower(x);
     6         return isdigit(x) || isalpha(x);
     7     }
     8     bool isPalindrome(string s) {
     9         if(s.length() == 0) return true;
    10         for(int i = 0, j = s.length() - 1; i < j; i ++, j --)
    11         {
    12             while(!valid(s[i]) && i < s.length()) i ++;
    13             while(!valid(s[j]) && j >= 0) j --;
    14             if(i < j && s[i] != s[j]) return false;
    15         }
    16         return true;
    17     }
    18 };
    View Code

    Binary Tree Maximum Path Sum

    后续遍历,子问题为子树根节点向叶子节点出发的最大路径和。

    即 l = DFS(now->left), r = DFS(now->right)。

    此时,ans可能是 now->valid,可能是左边一路上来加上now->valid,可能是右边一路上来,也可能是左边上来经过now再右边一路下去,四种情况。

    四种情况更新完ans后,now返回上一层只能是 now->valid或左边一路上来或右边一路上来,三种情况。

     1 /**
     2  * Definition for binary tree
     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     int ans;
    13     int DFS(TreeNode *now)
    14     {
    15         if(now == NULL) return 0;
    16         int l = max(DFS(now->left), 0);
    17         int r = max(DFS(now->right), 0);
    18         ans = max(ans, l + r + now->val);
    19         return max(l + now->val, r + now->val);
    20     }
    21     int maxPathSum(TreeNode *root) {
    22         if(root == NULL) return 0;
    23         ans = -0x3f3f3f3f;
    24         DFS(root);
    25         return ans;
    26     }
    27 };
    View Code

    Best Time to Buy and Sell Stock III

     前缀pre[i]处理 0 ~ i 买卖一次最优解,后缀suf[i]处理 i ~ prices.size() - 1 买卖一次最优解。

    所有位置pre[i] + suf[i]最大值为答案O(n)。

    处理最优解的时候是维护前(后)缀prices最小(大)值,与当前prices做差后和前(后)缀最优解比较取最优,O(n)。

    总复杂度O(n)。

     1 class Solution {
     2 public:
     3     int maxProfit(vector<int> &prices) {
     4         int ans = 0;
     5         vector<int> pre(prices.size()), suf(prices.size());
     6         for(int i = 0, mtmp = 0x3f3f3f3f; i < prices.size(); i ++)
     7         {
     8             mtmp = i ? min(mtmp, prices[i]) : prices[i];
     9             pre[i] = max(prices[i] - mtmp, i ? pre[i - 1] : 0);
    10         }
    11         for(int i = prices.size() - 1, mtmp = 0; i >= 0; i --)
    12         {
    13             mtmp = i != prices.size() - 1 ? max(mtmp, prices[i]) : prices[i];
    14             suf[i] = max(mtmp - prices[i], i != prices.size() - 1 ? suf[i + 1] : 0);
    15         }
    16         for(int i = 0; i < prices.size(); i ++)
    17             ans = max(ans, pre[i] + suf[i]);
    18         return ans;
    19     }
    20 };
    View Code

    Best Time to Buy and Sell Stock II

     可以买卖多次,把所有上坡差累加即可。

     1 class Solution {
     2 public:
     3     int maxProfit(vector<int> &prices) {
     4         int ans = 0;
     5         for(int i = 1; i < prices.size(); i ++)
     6         {
     7             if(prices[i] > prices[i - 1])
     8                 ans += prices[i] - prices[i - 1];
     9         }
    10         return ans;
    11     }
    12 };
    View Code

    Best Time to Buy and Sell Stock

     维护前(后)缀最小(大)值,和当前prices做差更新答案。

     1 class Solution {
     2 public:
     3     int maxProfit(vector<int> &prices) {
     4         int ans = 0;
     5         for(int i = prices.size() - 1, mtmp = 0; i >= 0; i --)
     6         {
     7             mtmp = max(mtmp, prices[i]);
     8             ans = max(mtmp - prices[i], ans);
     9         }
    10         return ans;
    11     }
    12 };
    View Code

    Triangle

    竟然遇到了ACM递推入门题,想必无数ACMer对这题太熟悉了。

    从下往上递推,一维数组滚动更新即可。这里懒省事,直接把原数组改了。

     1 class Solution {
     2 public:
     3     int minimumTotal(vector<vector<int> > &triangle) {
     4         for(int i = triangle.size() - 2; i >= 0; i --)
     5         {
     6             for(int j = 0; j < triangle[i].size(); j ++)
     7                 triangle[i][j] = min(triangle[i][j] + triangle[i + 1][j], triangle[i][j] + triangle[i + 1][j + 1]);
     8         }
     9         return triangle.size() == 0 ? 0 : triangle[0][0];
    10     }
    11 };
    View Code

    Pascal's Triangle II

     滚动数组递推,从后往前以便不破坏上一层递推数据。

     1 class Solution {
     2 public:
     3     vector<int> getRow(int rowIndex) {
     4         vector<int> ans(rowIndex + 1, 0);
     5         ans[0] = 1;
     6         for(int i = 0; i <= rowIndex; i ++)
     7         {
     8             for(int j = i; j >= 0; j --)
     9             {
    10                 ans[j] = (i == 0 || j == 0 || j == i ? 1 : ans[j] + ans[j - 1]);
    11             }
    12         }
    13         return ans;
    14     }
    15 };
    View Code

    Pascal's Triangle

     递推。。

     1 class Solution {
     2 public:
     3     vector<vector<int> > generate(int numRows) {
     4         vector<vector<int> > v;
     5         for(int i = 0; i < numRows; i ++)
     6         {
     7             vector<int> tmp;
     8             for(int j = 0; j <= i; j ++)
     9             {
    10                 tmp.push_back(i == 0 || j == 0 || j == i ? 1 : v[i - 1][j] + v[i - 1][j - 1]);
    11             }
    12             v.push_back(tmp);
    13         }
    14         return v;
    15     }
    16 };
    View Code

    Populating Next Right Pointers in Each Node II

     题目要求空间复杂度O(1),所以递归、队列等传统方法不应该用。

    本题可以利用生成的next指针来横向扫描,即得到一层的next指针之后,可以利用这一层的next指针来给下一层的next指针赋值。

     1 /**
     2  * Definition for binary tree with next pointer.
     3  * struct TreeLinkNode {
     4  *  int val;
     5  *  TreeLinkNode *left, *right, *next;
     6  *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     TreeLinkNode *findNext(TreeLinkNode *head)
    12     {
    13         while(head != NULL && head->left == NULL && head->right == NULL)
    14             head = head->next;
    15         return head;
    16     }
    17     void connect(TreeLinkNode *root) {
    18         if(root == NULL) return;
    19         TreeLinkNode *head, *last, *nexhead;
    20         for(head = root; head != NULL; head = nexhead)
    21         {
    22             head = findNext(head);
    23             if(head == NULL) break;
    24             if(head->left != NULL) nexhead = head->left;
    25             else nexhead = head->right;
    26             for(last = NULL; head != NULL; last = head, head = findNext(head->next))
    27             {
    28                 if(head->left != NULL && head->right != NULL)
    29                     head->left->next = head->right;
    30                 if(last == NULL) continue;
    31                 if(last->right != NULL) 
    32                     last->right->next = head->left != NULL ? head->left : head->right;
    33                 else 
    34                     last->left->next = head->left != NULL ? head->left : head->right;
    35             }
    36         }
    37     }
    38 };
    View Code

    Populating Next Right Pointers in Each Node

     不用考虑连续的空指针,就不用额外实现找下一个子树非空节点,比Populating Next Right Pointers in Each Node II 容易处理。

     1 /**
     2  * Definition for binary tree with next pointer.
     3  * struct TreeLinkNode {
     4  *  int val;
     5  *  TreeLinkNode *left, *right, *next;
     6  *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     void connect(TreeLinkNode *root) {
    12         if(root == NULL) return;
    13         TreeLinkNode *head, *nexhead, *last;
    14         for(head = root; head->left != NULL; head = nexhead)
    15         {
    16             nexhead = head->left;
    17             last = NULL;
    18             while(head != NULL)
    19             {
    20                 head->left->next = head->right;
    21                 if(last != NULL) last->right->next = head->left;
    22                 last = head;
    23                 head = head->next;
    24             }
    25         }
    26     }
    27 };
    View Code

    Distinct Subsequences

     典型动态规划。dp[i][j] 表示 T 的前 j 个字符在 S 的前 i 个字符中的解。

    对于dp[i + 1][j + 1],由两部分组成:

    一、 j + 1 对应到 S 前 i 个字符中的解,忽略 S 的第 i + 1 个字符。

    二、判断 S 的第 i + 1 个字符是否和 T 的第 j + 1 个字符相同,如果相同,则加上dp[i][j],否则不加。

     1 class Solution {
     2 public:
     3     int numDistinct(string S, string T) {
     4         if(S.length() < T.length()) return 0;
     5         vector<vector<int> > dp(S.length() + 1, vector<int>(T.length() + 1, 0));
     6         for(int i = 0; i < S.length(); i ++) dp[i][0] = 1;
     7         dp[0][1] = 0;
     8         for(int i = 0; i < S.length(); i ++)
     9         {
    10             for(int j = 0; j < T.length(); j ++)
    11             {
    12                 dp[i + 1][j + 1] = dp[i][j + 1];
    13                 if(S[i] == T[j]) dp[i + 1][j + 1] += dp[i][j];
    14             }
    15         }
    16         return dp[S.length()][T.length()];
    17     }
    18 };
    View Code

    Flatten Binary Tree to Linked List

     题意是优先左子树靠前,且排成一列用右子树指针,不管val的大小关系。

    后序遍历一遍即可,递归返回子树中尾节点指针,注意各种条件判断。

     1 /**
     2  * Definition for binary tree
     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 *DFS(TreeNode *now)
    13     {
    14         if(now->left == NULL && now->right == NULL) return now;
    15         TreeNode *leftok = NULL, *rightok = NULL;
    16         if(now->left != NULL) leftok = DFS(now->left);
    17         if(now->right != NULL) rightok = DFS(now->right);
    18         if(leftok != NULL)
    19         {
    20             leftok->right = now->right;
    21             now->right = now->left;
    22             now->left = NULL;
    23             return rightok ? rightok : leftok;
    24         }
    25         else return rightok;
    26     }
    27     void flatten(TreeNode *root) {
    28         if(root == NULL) return;
    29         DFS(root);
    30     }
    31 };
    View Code

    Path Sum II

     传统递归,把路径上的数字插入vector,终点判断是否插入答案。

     1 /**
     2  * Definition for binary tree
     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     int goal;
    13     vector<vector<int> >v;
    14     vector<int> curv;
    15     void DFS(TreeNode *now, int cursum)
    16     {
    17         curv.push_back(now->val);
    18         if(now->left == NULL && now->right == NULL) 
    19         {
    20             if(cursum + now->val == goal)
    21             {
    22                 v.push_back(curv);
    23                 curv.pop_back();
    24                 return;
    25             }
    26         }
    27         if(now->left != NULL) DFS(now->left, cursum + now->val);
    28         if(now->right != NULL) DFS(now->right, cursum + now->val);
    29         curv.pop_back();
    30     }
    31     vector<vector<int> > pathSum(TreeNode *root, int sum) {
    32         goal = sum;
    33         if(root == NULL) return v;
    34         DFS(root, 0);
    35         return v;
    36     }
    37 };
    View Code

    Path Sum

    遍历树。

     1 /**
     2  * Definition for binary tree
     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     int goal;
    13     bool DFS(TreeNode *now, int cursum)
    14     {
    15         if(now->left == NULL && now->right == NULL) 
    16             return cursum + now->val == goal;
    17         if(now->left != NULL && DFS(now->left, cursum + now->val)) return true;
    18         if(now->right != NULL && DFS(now->right, cursum + now->val)) return true;
    19     }
    20     bool hasPathSum(TreeNode *root, int sum) {
    21         goal = sum;
    22         if(root == NULL) return false;
    23         return DFS(root, 0);
    24     }
    25 };
    View Code

    Minimum Depth of Binary Tree

     还是遍历。

     1 /**
     2  * Definition for binary tree
     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     int minDepth(TreeNode *root) {
    13         if(root == NULL) return 0;
    14         if(root->left == NULL) return minDepth(root->right) + 1;
    15         else if(root->right == NULL) return minDepth(root->left) + 1;
    16         else return min(minDepth(root->left), minDepth(root->right)) + 1;
    17     }
    18 };
    View Code

    Balanced Binary Tree

    遍历。

     1 /**
     2  * Definition for binary tree
     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     int maxDepth(TreeNode *now)
    13     {
    14         if(now == NULL) return 0;
    15         int l = maxDepth(now->left) + 1;
    16         int r = maxDepth(now->right) + 1;
    17         return abs(l - r) > 1 || l < 0 || r < 0 ? -2 : max(l, r);
    18     }
    19     bool isBalanced(TreeNode *root) {
    20         return maxDepth(root) >= 0;
    21     }
    22 };
    View Code

    Convert Sorted List to Binary Search Tree

    每次找中点作为根节点,将两边递归,返回根节点指针作为左右节点。

     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  * Definition for binary tree
    11  * struct TreeNode {
    12  *     int val;
    13  *     TreeNode *left;
    14  *     TreeNode *right;
    15  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    16  * };
    17  */
    18 class Solution {
    19 public:
    20     TreeNode *sortedListToBST(ListNode *head) {
    21         if(head == NULL) return NULL;
    22         ListNode *p, *mid, *pre;
    23         for(p = mid = head, pre = NULL; p->next != NULL; mid = mid->next)
    24         {
    25             p = p->next;
    26             if(p->next == NULL) break;
    27             p = p->next;
    28             pre = mid;
    29         };
    30         TreeNode *root = new TreeNode(mid->val);
    31         if(pre != NULL) pre->next = NULL, root->left = sortedListToBST(head);
    32         else root->left = NULL;
    33         root->right = sortedListToBST(mid->next);
    34         if(pre != NULL) pre->next = mid;
    35         return root;
    36     }
    37 };
    View Code

      

    Convert Sorted Array to Binary Search Tree

     递归做,比链表的容易些。

     1 /**
     2  * Definition for binary tree
     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 *convert(vector<int> &num, int left, int right)
    13     {
    14         if(right == left) return NULL;
    15         int mid = right + left >> 1;
    16         TreeNode *root = new TreeNode(num[mid]);
    17         root->left = convert(num, left, mid);
    18         root->right = convert(num, mid + 1, right);
    19     }
    20     TreeNode *sortedArrayToBST(vector<int> &num) {
    21         return convert(num, 0, num.size());
    22     }
    23 };
    View Code

      

    Binary Tree Level Order Traversal II

     宽搜和深搜都可以,找对层数就行了。

    本以为这题亮点是如何一遍实现从底向上顺序的vector,AC之后上网一查也全是最后把vector翻转的。。。

     1 /**
     2  * Definition for binary tree
     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> >v;
    13     void DFS(TreeNode *now, int depth)
    14     {
    15         if(v.size() <= depth) v.push_back(vector<int>(0));
    16         v[depth].push_back(now->val);
    17         if(now->left != NULL) DFS(now->left, depth + 1);
    18         if(now->right != NULL) DFS(now->right, depth + 1);
    19     }
    20     vector<vector<int> > levelOrderBottom(TreeNode *root) {
    21         if(root == NULL) return v;
    22         DFS(root, 0);
    23         for(int i = 0, j = v.size() - 1; i < j; i ++, j --)
    24             swap(v[i], v[j]);
    25         return v;
    26     }
    27 };
    View Code

    Construct Binary Tree from Inorder and Postorder Traversal

    数据结构经典题。后序遍历的结尾是根节点 Proot,在中序遍历中找到这个节点 Iroot,则 Iroot两边即为左右子树。根据左右子树节点个数,在后序遍历中找到左右子树分界(左右子树肯定不交叉),则几个关键分界点都找到了,对左右子树递归。

     1 /**
     2  * Definition for binary tree
     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 *build(vector<int> &inorder, int ileft, int iright, vector<int> &postorder, int pleft, int pright)
    13     {
    14         if(iright == ileft)
    15             return NULL;
    16         int root;
    17         for(root = ileft; inorder[root] != postorder[pright - 1]; root ++);
    18         TreeNode *node = new TreeNode(inorder[root]);
    19         node->left = build(inorder, ileft, root, postorder, pleft, pleft + root - ileft);
    20         node->right = build(inorder, root + 1, iright, postorder, pleft + root - ileft, pright - 1);
    21         return node;
    22     }
    23     TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
    24         return build(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    25     }
    26 };
    View Code

    Construct Binary Tree from Preorder and Inorder Traversal

     和上一题Construct Binary Tree from Inorder and Postorder Traversal方法一样,前序和后序的信息作用相同。

     1 /**
     2  * Definition for binary tree
     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 *build(vector<int> &inorder, int ileft, int iright, vector<int> &preorder, int pleft, int pright)
    13     {
    14         if(iright == ileft)
    15             return NULL;
    16         int root;
    17         for(root = ileft; inorder[root] != preorder[pleft]; root ++);
    18         TreeNode *node = new TreeNode(inorder[root]);
    19         node->left = build(inorder, ileft, root, preorder, pleft + 1, pleft + root - ileft);
    20         node->right = build(inorder, root + 1, iright, preorder, pleft + root - ileft + 1, pright);
    21         return node;
    22     }
    23     TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
    24         return build(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    25         
    26     }
    27 };
    View Code

    Maximum Depth of Binary Tree

     遍历。

     1 /**
     2  * Definition for binary tree
     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     int maxDepth(TreeNode *root) {
    13         if(root == NULL) return 0;
    14         if(root->left == NULL) return maxDepth(root->right) + 1;
    15         if(root->right == NULL) return maxDepth(root->left) + 1;
    16         return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    17     }
    18 };
    View Code

    Binary Tree Zigzag Level Order Traversal

     BFS,奇偶层轮流走,一层左到右,一层右到左。

     1 /**
     2  * Definition for binary tree
     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> > ans;
    13     vector<vector<int> > zigzagLevelOrder(TreeNode *root) {
    14         if(root == NULL) return ans;
    15         vector<TreeNode*> q1, q2;
    16         q1.push_back(root);
    17         int depth = 0;
    18         while(!q1.empty() || !q2.empty())
    19         {
    20             ans.push_back(vector<int>(0));
    21             for(int i = q1.size() - 1; i >= 0; i --)
    22             {
    23                 ans[depth].push_back(q1[i]->val);
    24                 if(q1[i]->left != NULL) q2.push_back(q1[i]->left);
    25                 if(q1[i]->right != NULL) q2.push_back(q1[i]->right);
    26             }
    27             depth ++;
    28             q1.clear();
    29             if(q2.empty()) continue;
    30             ans.push_back(vector<int>(0));
    31             for(int i = q2.size() - 1; i >= 0; i --)
    32             {
    33                 ans[depth].push_back(q2[i]->val);
    34                 if(q2[i]->right != NULL) q1.push_back(q2[i]->right);
    35                 if(q2[i]->left != NULL) q1.push_back(q2[i]->left);
    36             }
    37             q2.clear();
    38             depth ++;
    39         }
    40         return ans;
    41     }
    42 };
    View Code

    Binary Tree Level Order Traversal

     懒省事直接在上一题Binary Tree Zigzag Level Order Traversal的代码上改了一下。

    只用一个队列的话,增加个层数信息存队列里即可。

     1 /**
     2  * Definition for binary tree
     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> > ans;
    13     vector<vector<int> > levelOrder(TreeNode *root) {
    14  if(root == NULL) return ans;
    15         vector<TreeNode*> q1, q2;
    16         q1.push_back(root);
    17         int depth = 0;
    18         while(!q1.empty() || !q2.empty())
    19         {
    20             ans.push_back(vector<int>(0));
    21             for(int i = 0; i < q1.size(); i ++)
    22             {
    23                 ans[depth].push_back(q1[i]->val);
    24                 if(q1[i]->left != NULL) q2.push_back(q1[i]->left);
    25                 if(q1[i]->right != NULL) q2.push_back(q1[i]->right);
    26             }
    27             depth ++;
    28             q1.clear();
    29             if(q2.empty()) continue;
    30             ans.push_back(vector<int>(0));
    31             for(int i = 0; i < q2.size(); i ++)
    32             {
    33                 ans[depth].push_back(q2[i]->val);
    34                 if(q2[i]->left != NULL) q1.push_back(q2[i]->left);
    35                 if(q2[i]->right != NULL) q1.push_back(q2[i]->right);
    36             }
    37             q2.clear();
    38             depth ++;
    39         }
    40         return ans;
    41     }
    42 };
    View Code

    Symmetric Tree

    递归:左指针和右指针,对称递归,即“左的左”和“右的右”对应,“左的右”和“右的左”对应。

     1 /**
     2  * Definition for binary tree
     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 *l, TreeNode *r)
    13     {
    14         if(l->val != r->val) return false;
    15         if(l->left != r->right && (l->left == NULL || r->right == NULL)
    16         || l->right != r->left && (l->right == NULL || r->left == NULL))
    17             return false;
    18         if(l->left != NULL && !judge(l->left, r->right)) return false;
    19         if(l->right != NULL && !judge(l->right, r->left)) return false;
    20         return true;
    21     }
    22     bool isSymmetric(TreeNode *root) {
    23         if(root == NULL) return true;
    24         if(root->left == NULL && root->right == NULL) return true;
    25         else if(root->left != NULL && root->right == NULL
    26             || root->left == NULL && root->right != NULL) return false;
    27         return judge(root->left, root->right);
    28     }
    29 };
    View Code

    非递归:左右子树分别做一个队列,同步遍历。

     1 /**
     2  * Definition for binary tree
     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 isSymmetric(TreeNode *root) {
    13         if(root == NULL) return true;
    14         if(root->left == NULL && root->right == NULL) return true;
    15         else if(root->left != NULL && root->right == NULL
    16             || root->left == NULL && root->right != NULL) return false;
    17         queue<TreeNode *> q1, q2;
    18         q1.push(root->left);
    19         q2.push(root->right);
    20         while(!q1.empty())
    21         {
    22             TreeNode *now1 = q1.front(), *now2 = q2.front();
    23             q1.pop();
    24             q2.pop();
    25             if(now1->val != now2->val) return false;
    26             if(now1->left != NULL || now2->right != NULL)
    27             {
    28                 if(now1->left == NULL || now2->right == NULL) return false;
    29                 q1.push(now1->left);
    30                 q2.push(now2->right);
    31             }
    32             if(now1->right != NULL || now2->left != NULL)
    33             {
    34                 if(now1->right == NULL || now2->left == NULL) return false;
    35                 q1.push(now1->right);
    36                 q2.push(now2->left);
    37             }
    38         }
    39         return true;
    40     }
    41 };
    View Code

    Same Tree

     同步遍历,比较判断。

     1 /**
     2  * Definition for binary tree
     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 isSameTree(TreeNode *p, TreeNode *q) {
    13         if(p == NULL && q == NULL) return true;
    14         if(p != q && (p == NULL || q == NULL) || p->val != q->val) return false;
    15         return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
    16     }
    17 };
    View Code

    Recover Binary Search Tree

     中序遍历是二叉查找树的顺序遍历,*a, *b表示前驱节点和当前节点,因为只有一对数值翻转了,所以肯定会遇到前驱节点val比当前节点val大的情况一次或两次,遇到一次表示翻转的是相邻的两个节点。*ans1和*ans2指向两个被翻转的节点,当遇到前驱val比当前val大的情况时候,根据第一次还是第二次给ans1和ans2赋值,最终翻转回来。

     1 /**
     2  * Definition for binary tree
     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 *a, *b;
    13     TreeNode *ans1, *ans2;
    14     bool DFS(TreeNode *now)
    15     {
    16         if(now->left != NULL)
    17             DFS(now->left);
    18         a = b;
    19         b = now;
    20         if(a != NULL && a->val > b->val)
    21         {
    22             if(ans1 == NULL) ans1 = a;
    23             ans2 = b;
    24         }
    25         if(now->right != NULL)
    26             DFS(now->right);
    27     }
    28     void recoverTree(TreeNode *root) {
    29         if(root == NULL) return;
    30         a = b = ans1 = ans2 = NULL;
    31         DFS(root);
    32         swap(ans1->val, ans2->val);
    33     }
    34 };
    View Code

    Validate Binary Search Tree

     中序遍历,更新前驱节点,与当前节点比较。

     1 /**
     2  * Definition for binary tree
     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 *pre = NULL;
    13     bool isValidBST(TreeNode *root) {
    14         if(root == NULL) return true;
    15         if(root->left != NULL && !isValidBST(root->left)) return false;
    16         if(pre != NULL && pre->val >= root->val) return false;
    17         pre = root;
    18         if(root->right != NULL && !isValidBST(root->right)) return false;
    19         return true;
    20     }
    21 };
    View Code

    Interleaving String

     动态规划。如果结果是true,则任意 i, j,s1 i 之前的字符 和 s2 j 之前的字符,都能够交叉为 s3 i + j 之前的字符。

    由此,当dp[i][j]时,如果s1[i]==s3[i+j],则尝试s1[i]与s3[i+j]对应,如果dp[i-1][j]是true,则dp[i][j]也为true。如果s2[j]==s3[i+j]则同样处理。

    直到最后,判断dp[s1.length()-1][s2.length()-1]是否为true。为方便初始化,坐标后移了一位。

    题目不厚道的出了s1.length()+s2.length() != s3.length()的数据,特判一下。

    看到网上也都是O(n^2)的解法,我也就放心了。。。

     1 class Solution {
     2 public:
     3     bool isInterleave(string s1, string s2, string s3) {
     4         if(s1.length() + s2.length() != s3.length()) return false;
     5         vector<vector<bool> > dp(s1.length() + 1, vector<bool>(s2.length() + 1, false));
     6         for(int i = 0; i <= s1.length(); i ++)
     7             for(int j = 0; j <= s2.length(); j ++)
     8             {
     9                 if(!i && !j) dp[i][j] = true;
    10                 dp[i][j] = dp[i][j] || i > 0 && s3[i + j - 1] == s1[i - 1] && dp[i - 1][j];
    11                 dp[i][j] = dp[i][j] || j > 0 && s3[i + j - 1] == s2[j - 1] && dp[i][j - 1];
    12             }
    13         return dp[s1.length()][s2.length()];
    14     }
    15 };
    View Code

    Unique Binary Search Trees II

    LeetCode目前为止感觉最暴力的。递归遍历所有情况,每次返回子问题(左右子树)的vector<TreeNode *>的解,两层循环组合这些解。

     1 /**
     2  * Definition for binary tree
     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<TreeNode *> generate(int start, int end)
    13     {
    14         vector<TreeNode *>res;
    15         if(start > end)
    16         {
    17             TreeNode *tmp = NULL;
    18             res.push_back(tmp);
    19             return res;
    20         }
    21         for(int i = start; i <= end; i ++)
    22         {
    23             vector<TreeNode *> l = generate(start, i - 1), r = generate(i + 1, end);
    24             for(int j = 0; j < l.size(); j ++)
    25                 for(int k = 0; k < r.size(); k ++)
    26                 {
    27                     TreeNode *tmp = new TreeNode(i);
    28                     tmp->left = l[j];
    29                     tmp->right = r[k];
    30                     res.push_back(tmp);
    31                 }
    32         }
    33         return res;
    34     }
    35     vector<TreeNode *> generateTrees(int n) {
    36         return generate(1, n);
    37     }
    38 };
    View Code

    Unique Binary Search Trees

     经典问题,卡特兰数,可递推,可用公式(公式用组合数,也要写循环)。

     1 class Solution {
     2 public:
     3     int COM(int n, int m)
     4     {
     5         m = n - m < m ? n - m : m;
     6         int res, i, j;
     7         for(i = n, res = j = 1; i > n - m; i --)
     8         {
     9             res *= i;
    10             for(; j <= m && res % j == 0; j ++)
    11                 res /= j;
    12         }
    13         return res;
    14     }
    15     int numTrees(int n) {
    16         return COM(n << 1, n) / (n + 1);
    17 
    18     }
    19 };
    View Code

    Binary Tree Inorder Traversal

     数据结构基础

     1 /**
     2  * Definition for binary tree
     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<int> res;
    13     void inorder(TreeNode *now)
    14     {
    15         if(now == NULL) return;
    16         inorder(now->left);
    17         res.push_back(now->val);
    18         inorder(now->right);
    19     }
    20     vector<int> inorderTraversal(TreeNode *root) {
    21         inorder(root);
    22         return res;
    23     }
    24 };
    View Code

    Restore IP Addresses

    四层递归枚举分割位置,判断数字范围和前导零,处理字符串。

     1 class Solution {
     2 public:
     3     vector<string> res;
     4     void DFS(string s, int last, int cur, string now)
     5     {
     6         if(cur == 3)
     7         {
     8             if(last == s.length()) return;
     9             string tmp = s.substr(last, s.length() - last);
    10             if(atoi(tmp.c_str()) <= 255 && (tmp.length() == 1 || tmp[0] != '0'))
    11                 res.push_back(now + tmp);
    12             return;
    13         }
    14         string lin;
    15         for(int i = last; i < s.length(); i ++)
    16         {
    17             string tmp = s.substr(last, i - last + 1);
    18             if(atoi(tmp.c_str()) <= 255 && (tmp.length() == 1 || tmp[0] != '0'))
    19                 DFS(s, i + 1, cur + 1, now + tmp + ".");
    20         }
    21     }
    22     vector<string> restoreIpAddresses(string s) {
    23         DFS(s, 0, 0, "");
    24         return res;
    25     }
    26 };
    View Code

    Reverse Linked List II

     在表头添加一个“哨兵”会好写很多,额外的newhead可以帮助标记翻转之后更换了的头指针。

     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 *reverseBetween(ListNode *head, int m, int n) {
    12         ListNode *newhead = new ListNode(0);
    13         newhead->next = head;
    14         ListNode *pre = newhead, *p = head, *start = NULL;
    15         ListNode *tmp;
    16         for(int i = 1; p != NULL; i ++)
    17         {
    18             tmp = p->next;
    19             if(i == m)
    20                 start = pre;
    21             if(i > m && i <= n)
    22                 p->next = pre;
    23             if(i == n)
    24             {
    25                 start->next->next = tmp;
    26                 start->next = p;
    27             }
    28             pre = p;
    29             p = tmp;
    30         }
    31         tmp = newhead->next;
    32         free(newhead);
    33         return tmp;
    34     }
    35 };
    View Code

    Subsets II

    统计地存map里,map[i]= j 表示 S 中有 j 个 i。map是有序的,用迭代器递归枚举放入集合的个数。

    也可以先排序,用set标记每个数时候被放入过,第一次放入之后才可以继续放同一个数。

    代码是用map的方法。

     1 class Solution {
     2 public:
     3     vector<vector<int> > res;
     4     vector<int> now;
     5     map<int, int> mp;
     6     void DFS(map<int, int>::iterator i)
     7     {
     8         if(i == mp.end())
     9         {
    10             res.push_back(now);
    11             return;
    12         }
    13         map<int, int>::iterator tmp = i;
    14         i ++;
    15         DFS(i);
    16         for(int j = 0; j < tmp->second; j ++)
    17         {
    18             now.push_back(tmp->first);
    19             DFS(i);
    20         }
    21         for(int j = 0; j < tmp->second; j ++)
    22             now.pop_back();
    23     }
    24     vector<vector<int> > subsetsWithDup(vector<int> &S) {
    25         for(int i = 0; i < S.size(); i ++)
    26             !mp.count(S[i]) ? (mp[S[i]] = 1) : mp[S[i]] ++;
    27         DFS(mp.begin());
    28         return res;
    29     }
    30 };
    View Code

    Decode Ways

    递推:dp[i]表示前 i 个数字的解码种数。

    dp[i]  = if(一)dp[i-1] + if(二)dp[i-2]

    当 i 位置不为0,可加上 i - 1 位置的解。当当前位置和前一位置组成的两位数满足解码且高位不为0,可加上 i - 2 位置的解。

     1 class Solution {
     2 public:
     3     int numDecodings(string s) {
     4         if(s.length() == 0) return 0;
     5         vector<int> dp(s.length() + 1, 0);
     6         dp[0] = 1;
     7         for(int i = 0; i < s.length(); i ++)
     8         {
     9             dp[i + 1] = (s[i] != '0' ? dp[i] : 0) +
    10                 (i > 0 && s[i - 1] != '0' && atoi(s.substr(i - 1, 2).c_str()) <= 26 ? dp[i - 1] : 0);
    11         }
    12         return dp[s.length()];
    13     }
    14 };
    View Code

    Gray Code

    格雷码有多种生成方法,可参考维基百科

    1 class Solution {
    2 public:
    3     vector<int> grayCode(int n) {
    4         vector<int> res;
    5         for(int i = 0; i < (1 << n); i ++)
    6             res.push_back((i >> 1) ^ i);
    7         return res;
    8     }
    9 };
    View Code

    Merge Sorted Array

     从后往前,对 A 来说一个萝卜一个坑,肯定不会破坏前面的数据。具体看代码。

     1 class Solution {
     2 public:
     3     void merge(int A[], int m, int B[], int n) {
     4         int p = m + n - 1, i = m - 1, j = n - 1;
     5         for(; i >= 0 && j >= 0;)
     6         {
     7             if(A[i] > B[j]) A[p --] = A[i --];
     8             else A[p --] = B[j --];
     9         }
    10         while(i >= 0) A[p --] = A[i --];
    11         while(j >= 0) A[p --] = B[j --];
    12     }
    13 };
    View Code

    Scramble String

     直接搜索可以过,记忆化搜索可提高效率。

     dp[i][j][k]表示从 s1[i] 和 s2[j] 开始长度为 k 的字符串是否是scrambled string

    枚举分割位置,scrambled string要求字符串对应字母的个数是一致的,可以直接排序对比。递归终点是刚好只有一个字母。

     1 class Solution {
     2 public:
     3     string S1, S2;
     4     vector<vector<vector<int> > > dp;
     5     bool judge(string a, string b)
     6     {
     7         sort(a.begin(), a.end());
     8         sort(b.begin(), b.end());
     9         for(int i = 0; i < a.length(); i ++)
    10             if(a[i] != b[i]) return false;
    11         return true;
    12     }
    13     int DFS(int s1start, int s2start, int len)
    14     {
    15         int &ans = dp[s1start][s2start][len - 1];
    16         if(len == 1) return ans = S1[s1start] == S2[s2start];
    17         if(ans != -1) return ans;
    18         if(!judge(S1.substr(s1start, len), S2.substr(s2start, len))) return ans = 0;
    19         ans = 0;
    20         for(int i = 1; i < len; i ++)
    21         {
    22             ans = ans 
    23             || DFS(s1start, s2start, i) && DFS(s1start + i, s2start + i, len - i)
    24             || DFS(s1start, s2start + len - i, i) && DFS(s1start + i, s2start, len - i);
    25 
    26         }
    27         return ans;
    28     }
    29     bool isScramble(string s1, string s2) {
    30         S1 = s1, S2 = s2;
    31         dp = vector<vector<vector<int> > >
    32             (s1.length(), vector<vector<int> >
    33                 (s1.length(), vector<int>
    34                     (s1.length(), -1)));
    35         return DFS(0, 0, s1.length());
    36     }
    37 };
    View Code

    Partition List

     分存大小最后合并。

     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 *partition(ListNode *head, int x) {
    12         ListNode *shead, *bhead, *smaller, *bigger, *p;
    13         for(shead = bhead = smaller = bigger = NULL, p = head; p != NULL; p = p->next)
    14         {
    15             if(p->val < x)
    16             {
    17                 if(shead == NULL)
    18                     shead = p;
    19                 if(smaller != NULL)
    20                     smaller->next = p;
    21                 smaller = p;
    22             }
    23             else
    24             {
    25                 if(bhead == NULL)
    26                     bhead = p;
    27                 if(bigger != NULL)
    28                     bigger->next = p;
    29                 bigger = p;
    30             }
    31         }
    32         if(smaller != NULL) smaller->next = bhead;
    33         if(bigger != NULL) bigger->next = NULL;
    34         return shead != NULL ? shead : bhead;
    35     }
    36 };
    View Code

    Maximal Rectangle

    方法一:linecnt[i][j]统计第 i 行到第 j 位置有多少个连续的 '1',接下来枚举列,每一列相当于一次直方图最大矩形统计,计算每个位置向前和向后最远的不少于当前位置值的位置,每次更新结果,总复杂度O(n^2)。

    找“最远位置”用迭代指针,理论复杂度略高于O(n)。

     1 class Solution {
     2 public:
     3     int maximalRectangle(vector<vector<char> > &matrix) {
     4         if(matrix.size() == 0) return 0;
     5         int H = matrix.size(), W = matrix[0].size();
     6         int ans = 0;
     7         vector<int> left(H), right(H);
     8         vector<vector<int> > linecnt(H, vector<int>(W, 0));
     9         for(int i = 0; i < H; i ++)
    10         {
    11             int last = 0;
    12             for(int j = 0; j < W; j ++)
    13             {
    14                 if(matrix[i][j] == '1') last ++;
    15                 else last = 0;
    16                 linecnt[i][j] = last;
    17             }
    18         }
    19         for(int k = 0; k < W; k ++)
    20         {
    21             for(int i = 0; i < H; i ++)
    22             {
    23                 if(i == 0) left[i] = -1;
    24                 else
    25                 {
    26                     left[i] = i - 1;
    27                     while(left[i] > -1 && linecnt[left[i]][k] >= linecnt[i][k])
    28                         left[i] = left[left[i]];
    29                 }
    30             }
    31             for(int i = H - 1; i >= 0; i --)
    32             {
    33                 if(i == H - 1) right[i] = H;
    34                 else
    35                 {
    36                     right[i] = i + 1;
    37                     while(right[i] < H && linecnt[right[i]][k] >= linecnt[i][k])
    38                         right[i] = right[right[i]];
    39                 }
    40                 ans = max(ans, (right[i] - left[i] - 1) * linecnt[i][k]);
    41             }
    42         }
    43         return ans;
    44     }
    45 };
    View Code

    用单调栈,理论复杂度O(n)。

     1 class Solution {
     2 public:
     3     int maximalRectangle(vector<vector<char> > &matrix) {
     4         if(matrix.size() == 0) return 0;
     5         vector<vector<int> > linecnt(matrix.size(), vector<int>(matrix[0].size(), 0));
     6         for(int i = 0; i < matrix.size(); i ++)
     7         {
     8             int last = 0;
     9             for(int j = 0; j < matrix[0].size(); j ++)
    10             {
    11                 if(matrix[i][j] == '1') last ++;
    12                 else last = 0;
    13                 linecnt[i][j] = last;
    14             }
    15         }
    16         int ans = 0;
    17         for(int k = 0; k < matrix[0].size(); k ++)
    18         {
    19             stack<int> s, site;
    20             vector<int>last(matrix.size());
    21             for(int i = 0; i < matrix.size(); i ++)
    22             {
    23                 while(!s.empty() && s.top() >= linecnt[i][k])
    24                     s.pop(), site.pop();
    25                 if(!s.empty()) last[i] = site.top() + 1;
    26                 else last[i] = 0;
    27                 s.push(linecnt[i][k]);
    28                 site.push(i);
    29             }
    30             while(!s.empty()) s.pop(), site.pop();
    31             for(int i = matrix.size() - 1; i >= 0; i --)
    32             {
    33                 while(!s.empty() && s.top() >= linecnt[i][k])
    34                     s.pop(), site.pop();
    35                 if(!s.empty()) ans = max(ans, (site.top() - last[i]) * linecnt[i][k]);
    36                 else ans = max(ans, (int)(matrix.size() - last[i]) * linecnt[i][k]);
    37                 s.push(linecnt[i][k]);
    38                 site.push(i);
    39             }
    40         }
    41         return ans;
    42     }
    43 };
    View Code

    方法二:每个 '1' 的点当作一个矩形的底部,left[j]、right[j]、height[j]表示当前行第 j 个位置这个点向左、右、上伸展的最大矩形的边界,作为滚动数组,下一行的数据可以由上一行结果得到,总复杂度O(n^2)。

    left[j] = max(这一行最左, left[j](上一行最左)  );

    right[j] = min(这一行最右,right[j](上一行最右)  );

    height[j] = height[j - 1] + 1;

     1 class Solution {
     2 public:
     3     int maximalRectangle(vector<vector<char> > &matrix) {
     4         if(matrix.size() == 0) return 0;
     5         int H = matrix.size(), W = matrix[0].size();
     6         vector<int> left(W, -1), right(W, W), height(W, 0);
     7         int ans = 0;
     8         for(int i = 0; i < H; i ++)
     9         {
    10             int last = -1;
    11             for(int j = 0; j < W; j ++)
    12             {
    13                 if(matrix[i][j] == '1')
    14                 {
    15                     if(last == -1) last = j;
    16                     left[j] = max(left[j], last);
    17                     height[j] ++;
    18                 }
    19                 else
    20                 {
    21                     last = -1;
    22                     left[j] = -1;
    23                     height[j] = 0;
    24                 }
    25             }
    26             last = -1;
    27             for(int j = W - 1; j >= 0; j --)
    28             {
    29                 if(matrix[i][j] == '1')
    30                 {
    31                     if(last == -1) last = j;
    32                     right[j] = min(right[j], last);
    33                     ans = max(ans, height[j] * (right[j] - left[j] + 1));
    34                 }
    35                 else
    36                 {
    37                     last = -1;
    38                     right[j] = W;
    39                 }
    40             }
    41         }
    42         return ans;
    43     }
    44 };
    View Code

    Largest Rectangle in Histogram

     参考上一题Maximal Rectangle方法一。

     1 class Solution {
     2 public:
     3     int largestRectangleArea(vector<int> &height) {
     4         if(height.size() == 0) return 0;
     5         vector<int> left(height.size()), right(height.size());
     6         int ans = 0;
     7         for(int i = 0; i < height.size(); i ++)
     8         {
     9             if(i == 0) left[i] = -1;
    10             else
    11             {
    12                 left[i] = i - 1;
    13                 while(left[i] > -1 && height[i] <= height[left[i]])
    14                     left[i] = left[left[i]];
    15             }
    16         }
    17         for(int i = height.size() - 1; i >= 0; i --)
    18         {
    19             if(i == height.size() - 1) right[i] = height.size();
    20             else
    21             {
    22                 right[i] = i + 1;
    23                 while(right[i] < height.size() && height[i] <= height[right[i]])
    24                     right[i] = right[right[i]];
    25             }
    26             ans = max(ans, (right[i] - left[i] - 1) * height[i]);
    27         }
    28         return ans;
    29     }
    30 };
    View Code

    Remove Duplicates from Sorted List II

     加个表头乱搞吧。

     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 *deleteDuplicates(ListNode *head) {
    12         if(head == NULL || head->next == NULL) return head;
    13         ListNode *newhead = new ListNode(0);
    14         newhead->next = head;
    15         for(ListNode *pre = newhead, *now = head, *nex = head->next; nex != NULL;)
    16         {
    17             if(now->val == nex->val)
    18             {
    19                 while(nex != NULL && now->val == nex->val)
    20                 {
    21                     free(now);
    22                     now = nex;
    23                     nex = nex->next;
    24                 }
    25                 free(now);
    26                 pre->next = nex;
    27                 if(nex == NULL) break;
    28             }
    29             else pre = now;
    30             now = nex;
    31             nex = nex->next;
    32         }
    33         head = newhead->next;
    34         free(newhead);
    35         return head;
    36     }
    37 };
    View Code

    Remove Duplicates from Sorted List

     直接操作。

     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 *deleteDuplicates(ListNode *head) {
    12         if(head == NULL || head->next == NULL) return head;
    13         for(ListNode *pre = head, *p = head->next; p != NULL;)
    14         {
    15             while(p != NULL && pre->val == p->val)
    16             {
    17                 pre->next = p->next;
    18                 free(p);
    19                 p = pre->next;
    20             }
    21             if(p == NULL) break;
    22             pre = p;
    23             p = p->next;
    24         }
    25         return head;
    26     }
    27 };
    View Code

    Search in Rotated Sorted Array II

    以mid为界,左右两边至少有一边是有序的。由于不可避免地会有O(n)的可能性,所以确定的时候二分,不确定的时候单位缩减边界。

     1 class Solution {
     2 public:
     3     bool search(int A[], int n, int target) {
     4         int left = 0, right = n - 1, mid;
     5         while(left < right)
     6         {
     7             mid = left + right >> 1;
     8             if(target < A[mid] && A[left] < target) right = mid;
     9             else if(target < A[right] && A[mid] < target) left = mid + 1;
    10             else
    11             {
    12                 if(A[left] == target || A[right] == target) return true;
    13                 else if(A[left] < target) left ++;
    14                 else if(target < A[right]) right --;
    15                 else return false;
    16             }
    17         }
    18         return A[left] == target ? true : false;
    19     }
    20 };
    View Code

    Remove Duplicates from Sorted Array II

     记下放了几个,多了不放。

     1 class Solution {
     2 public:
     3     int removeDuplicates(int A[], int n) {
     4         int i, j, cnt;
     5         for(i = j = cnt = 0; i < n; i ++)
     6         {
     7             if(j != 0 && A[j - 1] == A[i]) cnt ++;
     8             else cnt = 0;
     9             if(cnt < 2) A[j ++] = A[i];
    10         }
    11         return j;
    12     }
    13 };
    View Code

    Word Search

    基础DFS。

     1 class Solution {
     2 public:
     3     int dx[4] = {1, -1, 0, 0};
     4     int dy[4] = {0, 0, 1, -1};
     5     bool DFS(int x, int y, vector<vector<char> > &board, string word, int ith)
     6     {
     7         if(board[x][y] != word[ith]) return false;
     8         if(ith == word.length() - 1) return true;
     9         board[x][y] = '.';
    10         for(int i = 0; i < 4; i ++)
    11         {
    12             int nx = x + dx[i];
    13             int ny = y + dy[i];
    14             if(nx >= 0 && ny >= 0 && nx < board.size() && ny < board[0].size())
    15             {
    16                 if(DFS(nx, ny, board, word, ith + 1))
    17                 {
    18                     board[x][y] = word[ith];
    19                     return true;
    20                 }
    21             }
    22         }
    23         board[x][y] = word[ith];
    24         return false;
    25     }
    26     bool exist(vector<vector<char> > &board, string word) {
    27         for(int i = 0; i < board.size(); i ++)
    28         {
    29             for(int j = 0; j < board[0].size(); j ++)
    30             {
    31                 if(DFS(i, j, board, word, 0)) return true;
    32             }
    33         }
    34         return false;
    35     }
    36 };
    View Code

    Subsets

    基础DFS。

     1 class Solution {
     2 public:
     3     vector<int> now;
     4     vector<vector<int> > res;
     5     void DFS(vector<int> &S, int ith)
     6     {
     7         if(ith == S.size())
     8         {
     9             res.push_back(now);
    10             return;
    11         }
    12         DFS(S, ith + 1);
    13         now.push_back(S[ith]);
    14         DFS(S, ith + 1);
    15         now.pop_back();
    16     }
    17     vector<vector<int> > subsets(vector<int> &S) {
    18         sort(S.begin(), S.end());
    19         DFS(S, 0);
    20         return res;
    21     }
    22 };
    View Code

    Combinations

    基础DFS。

     1 class Solution {
     2 public:
     3     vector<int> now;
     4     vector<vector<int> > res;
     5     void DFS(int n, int ith, int sum, int k)
     6     {
     7         if(sum == k)
     8         {
     9             res.push_back(now);
    10             return;
    11         }
    12         if(sum + n - ith + 1 > k)
    13         {
    14             DFS(n, ith + 1, sum, k);
    15         }
    16         now.push_back(ith);
    17         DFS(n, ith + 1, sum + 1, k);
    18         now.pop_back();
    19     }
    20     vector<vector<int> > combine(int n, int k) {
    21         DFS(n, 1, 0, k);
    22         return res;
    23     }
    24 };
    View Code

    Minimum Window Substring

    先统计 T 中各字符都有多少个,然后两个下标一前(i)一后(j)在 S 上跑, 当 i 跑到把 T 中字符都包含的位置时候,让 j 追到第一个包含 T 的字符的地方,更新结果,去掉 j 这个位置字符的统计,让 i 继续跑,如此反复。

    i 和 j 都只遍历一遍 S,复杂度 O(n)。

     1 class Solution {
     2 public:
     3     string minWindow(string S, string T) {
     4         vector<int> cnt(256, 0), need(256, 0);
     5         int sum = 0, len = 0x3f3f3f3f;
     6         string ans;
     7         for(int i = 0; i < T.size(); i ++)
     8             need[T[i]] ++;
     9         for(int i = 0, j = 0; i < S.length(); j ++)
    10         {
    11             while(i < S.length() && sum < T.length())
    12             {
    13                 if(cnt[S[i]] < need[S[i]])
    14                     sum ++;
    15                 cnt[S[i]] ++;
    16                 i ++;
    17             }
    18             while(sum == T.length() && j < S.length())
    19             {
    20                 cnt[S[j]] --;
    21                 if(cnt[S[j]] < need[S[j]])
    22                     break;
    23                 j ++;
    24             }
    25             if(sum < T.length()) break;
    26             if(i - j < len)
    27                 ans = S.substr(j, i - j), len = i - j;
    28             sum --;
    29         }
    30         return ans;
    31     }
    32 };
    View Code

    Sort Colors

    轮流找:

     1 class Solution {
     2 public:
     3     void sortColors(int A[], int n) {
     4         int find = 0;
     5         for(int i = 0, j = n - 1; i < n; i ++)
     6         {
     7             if(A[i] == find) continue;
     8             while(j > i && A[j] != find) j --;
     9             if(j > i) swap(A[i], A[j]);
    10             else i --, j = n - 1, find ++;
    11         }
    12     }
    13 };
    View Code

    找到哪个放哪个:

     1 class Solution {
     2 public:
     3     void sortColors(int A[], int n) {
     4         int p0, p1, p2;
     5         for(p0 = 0, p1 = p2 = n - 1; p0 < p1; )
     6         {
     7             if(A[p0] == 0) p0 ++;
     8             if(A[p0] == 1) swap(A[p0], A[p1 --]);
     9             if(A[p0] == 2)
    10             {
    11                 swap(A[p0], A[p2 --]);
    12                 p1 = p2;
    13             }
    14         }
    15     }
    16 };
    View Code

    Search a 2D Matrix

    写两个二分查找。或者把整个矩阵看作一维,直接二分,换算坐标。

     1 class Solution {
     2 public:
     3     bool searchMatrix(vector<vector<int> > &matrix, int target) {
     4         int left, right, mid;
     5         for(left = 0, right = matrix.size(); left < right - 1; )
     6         {
     7             mid = left + right >> 1;
     8             if(matrix[mid][0] > target) right = mid;
     9             else left = mid;
    10         }
    11         if(left == matrix.size() || right == 0) return false;
    12         vector<int> &a = matrix[left];
    13         for(left = 0, right = a.size(); left < right - 1;)
    14         {
    15             mid = left + right >> 1;
    16             if(a[mid] > target) right = mid;
    17             else left = mid;
    18         }
    19         if(left == a.size() || right == 0) return false;
    20         return a[left] == target;
    21     }
    22 };
    View Code

    Set Matrix Zeroes

    O(m+n)的方法是容易想到的,而空间复杂度O(1),只要利用原矩阵的一行和一列来使用O(m+n)的方法就行了。

     1 class Solution {
     2 public:
     3     void setZeroes(vector<vector<int> > &matrix) {
     4         if(matrix.size() == 0) return;
     5         int x = -1, y = -1;
     6         for(int i = 0; i < matrix.size(); i ++)
     7         {
     8             for(int j = 0; j < matrix[0].size(); j ++)
     9             {
    10                 if(matrix[i][j] == 0)
    11                 {
    12                     if(x == -1)
    13                     {
    14                         x = i, y = j;
    15                     }
    16                     else
    17                     {
    18                         matrix[x][j] = 0;
    19                         matrix[i][y] = 0;
    20                     }
    21                 }
    22             }
    23         }
    24         if(x == -1) return;
    25         for(int i = 0; i < matrix.size(); i ++)
    26             for(int j = 0; j < matrix[0].size(); j ++)
    27                 if((matrix[x][j] == 0 || matrix[i][y] == 0) && (i != x && j != y)) matrix[i][j] = 0;
    28         for(int i = 0; i < matrix.size(); i ++) matrix[i][y] = 0;
    29         for(int j = 0; j < matrix[0].size(); j ++) matrix[x][j] = 0;
    30     }
    31 };
    View Code

    Edit Distance

     动态规划,先初始化 dp[i][0] 和 dp[0][i],即每个字符串对应空串的编辑距离为串长度,之后对每个位置取子问题加上当前位置 改、删、增得解的最小值。

     1 class Solution {
     2 public:
     3     int minDistance(string word1, string word2) {
     4         vector<vector<int> > dp(word1.length() + 1, vector<int>(word2.length() + 1, 0));
     5         for(int i = 0; i < word1.length(); i ++) dp[i + 1][0] = i + 1;
     6         for(int i = 0; i < word2.length(); i ++) dp[0][i + 1] = i + 1;
     7         for(int i = 0; i < word1.length(); i ++)
     8             for(int j = 0; j < word2.length(); j ++)
     9             {
    10                 if(word1[i] != word2[j])
    11                     dp[i + 1][j + 1] = min(dp[i][j] + 1, min(dp[i][j + 1] + 1, dp[i + 1][j] + 1));
    12                 else
    13                     dp[i + 1][j + 1] = min(dp[i][j], min(dp[i][j + 1] + 1, dp[i + 1][j] + 1));
    14             }
    15         return dp[word1.length()][word2.length()];
    16     }
    17 };
    View Code

    Simplify Path

     好烦人的题,没什么好说的。

     1 class Solution {
     2 public:
     3     string simplifyPath(string path) {
     4         stack<string> s;
     5         string str;
     6         for(int i = 0; i < path.length(); i ++)
     7         {
     8             if(path[i] == '/')
     9             {
    10                 if(str == "..")
    11                 {
    12                     if(!s.empty()) 
    13                         s.pop();
    14                 }
    15                 else if(str != "." && str != "")
    16                     s.push(str);
    17                 str.clear();
    18             }
    19             else
    20                 str += path[i];
    21         }
    22         if(str == "..")
    23         {
    24             if(!s.empty())
    25                 s.pop();
    26         }
    27         else if(str != "." && str != "")
    28             s.push(str);
    29         if(s.empty()) return "/";
    30         for(str.clear(); !s.empty(); s.pop())
    31             str = "/" + s.top() + str;
    32         return str;
    33     }
    34 };
    View Code

    Climbing Stairs

     递推,就是斐波那契数列。

    1 class Solution {
    2 public:
    3     int climbStairs(int n) {
    4         return (int)
    5             (pow((1+sqrt(5))/2, n + 1) / sqrt(5) - 
    6             pow((1-sqrt(5))/2, n + 1) / sqrt(5) + 0.1);
    7     }
    8 };
    View Code

    Sqrt(x)

     牛顿迭代。

    设输入为n,f(x)=x^2-n,解就是f(x)=0时的x。

    设猜了一数x[0],那么在f(x)在x[0]处的切线与x轴的交点x[1]更接近目标解(可画图看看)。

    那么递推下去,x[i]=(x[i-1]+n/x[i-1])/2,用double,越推越精确,直到自己想要的精度。

     1 class Solution {
     2 public:
     3     int sqrt(int x) {
     4         double now, last;
     5         if(x == 0) return 0;
     6         for(now = last = (double)x; ; last = now)
     7         {
     8             now = (last + (x / last)) * 0.5;
     9             if(fabs(last - now) < 1e-5) break;
    10         }
    11         return (int)(now + 1e-6);
    12     }
    13 };
    View Code

    Text Justification

    每行限制长度,空格均匀插入,不能完全平均的情况下优先靠前的单词间隔。

    最后一行特别处理,单词间只有一个空格,剩下的放在末尾。

     1 class Solution {
     2 public:
     3     vector<string> fullJustify(vector<string> &words, int L) {
     4         vector<string> ans;
     5         int cnt = 0, i, j, k, l;
     6         for(i = 0, j = 0; j < words.size(); i ++)
     7         {
     8             if(i < words.size())
     9             {
    10                 cnt += words[i].length();
    11                 if(i == j) continue;
    12             }
    13             if(i == words.size() || (L - cnt) / (i - j) < 1)
    14             {
    15                 int blank = 0;
    16                 if(i < words.size()) blank = (i - j - 1) ? (L - cnt + words[i].length()) / (i - j - 1) : 0;
    17                 string tmp = "";
    18                 l = i < words.size() ? (L - cnt + words[i].length() - blank * (i - j - 1)) : 0;
    19                 for(k = j; k < i; k ++, l --)
    20                 {
    21                     tmp += words[k];
    22                     if(k != i - 1)
    23                     {
    24                         if(i != words.size())
    25                         {
    26                             for(int bl = 0; bl < blank; bl ++) tmp += " ";
    27                             if(l > 0) tmp += " ";
    28                         }
    29                         else
    30                             tmp += " ";
    31                     }
    32                 }
    33                 while(tmp.length() < L) tmp += " ";
    34                 ans.push_back(tmp);
    35                 cnt = 0;
    36                 j = i;
    37                 i --;
    38             }
    39         }
    40         return ans;
    41     }
    42 };
    View Code

    Plus One

    大整数加法。

     1 class Solution {
     2 public:
     3     vector<int> plusOne(vector<int> &digits) {
     4         int cur, i;
     5         if(digits.size() == 0) return digits;
     6         for(i = digits.size() - 1, cur = 1; i >= 0; i --)
     7         {
     8             int tmp = digits[i] + cur;
     9             cur = tmp / 10;
    10             digits[i] = tmp % 10;
    11         }
    12         if(cur) digits.insert(digits.begin(), cur);
    13         return digits;
    14     }
    15 };
    View Code

    Valid Number

    用DFA也不麻烦,题目定义太模糊,为了理解规则错很多次也没办法。

     1 class Solution {
     2 public:
     3 
     4     int f[11][129];
     5     const int fail = -1;    //非法
     6     const int st = 0;       //起始
     7     const int pn = 1;       //正负号
     8     const int di = 2;       //整数部分
     9     const int del = 3;      //前面无数字小数点
    10     const int ddi = 4;      //小数部分
    11     const int ndel = 5;     //前面有数字小数点
    12     const int dibl = 6;     //数后空格
    13     const int ex = 7;       //进入指数
    14     const int epn = 8;      //指数符号
    15     const int edi = 9;      //指数数字
    16     const int end = 10;     //正确结束
    17     void buildDFA()
    18     {
    19         memset(f, -1, sizeof(f));
    20         f[st][' '] = st;
    21         f[st]['+'] = f[st]['-'] = pn;
    22         for(int i = '0'; i <= '9'; i ++)
    23         {
    24             f[st][i] = f[pn][i] = f[di][i] = di;
    25             f[del][i] = f[ndel][i] = f[ddi][i] = ddi;
    26             f[ex][i] = f[epn][i] = f[edi][i] = edi;
    27         }
    28         f[di]['.'] = ndel;
    29         f[st]['.'] = f[pn]['.'] = del;
    30         f[di][' '] = f[ndel][' '] = f[ddi][' '] = f[dibl][' '] = f[edi][' '] = dibl;
    31         f[di][0] = f[ndel][0] = f[dibl][0] = f[ddi][0] = f[edi][0] = end;
    32         f[di]['e'] = f[ndel]['e'] = f[ddi]['e'] = ex;
    33         f[ex][' '] = ex;
    34         f[ex]['+'] = f[ex]['-'] = epn;
    35     }
    36     bool DFA(const char *s)
    37     {
    38         int situ = st;
    39         for(int i = 0;; i ++)
    40         {
    41             situ = f[situ][s[i]];
    42             if(situ == end) return true;
    43             if(situ == fail) return false;
    44         }
    45         return true;
    46     }
    47     bool isNumber(const char *s) {
    48         buildDFA();
    49         return DFA(s);
    50     }
    51 };
    View Code

    Add Binary

    翻转,大整数加法,再翻转。无心情优化。

     1 class Solution {
     2 public:
     3     string addBinary(string a, string b) {
     4         reverse(a.begin(), a.end());
     5         reverse(b.begin(), b.end());
     6         string c;
     7         int cur = 0, i;
     8         for(i = 0; i < min(a.length(), b.length()); i ++)
     9         {
    10             int tmp = a[i] - '0' + b[i] - '0' + cur;
    11             cur = tmp >> 1;
    12             c += (tmp & 1) + '0';
    13         }
    14         string &t = a.length() > b.length() ? a : b;
    15         for(; i < t.length(); i ++)
    16         {
    17             int tmp = t[i] - '0' + cur;
    18             cur = tmp >> 1;
    19             c += (tmp & 1) + '0';
    20         }
    21         if(cur) c += '1';
    22         reverse(c.begin(), c.end());
    23         return c;
    24     }
    25 };
    View Code

    Merge Two Sorted Lists

    归并排序的一次操作,设个哨兵头结点,结束后free。

     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 *mergeTwoLists(ListNode *l1, ListNode *l2) {
    12         ListNode *thead = new ListNode(0), *p = thead;
    13         while(l1 != NULL && l2 != NULL)
    14         {
    15             if(l1->val < l2->val) p->next = l1, p = l1, l1 = l1->next;
    16             else p->next = l2, p = l2, l2 = l2->next;
    17         }
    18         while(l1 != NULL) p->next = l1, p = l1, l1 = l1->next;
    19         while(l2 != NULL) p->next = l2, p = l2, l2 = l2->next;
    20         p = thead->next;
    21         free(thead);
    22         return p;
    23     }
    24 };
    View Code

    Minimum Path Sum

    递推

     1 class Solution {
     2 public:
     3     int minPathSum(vector<vector<int> > &grid) {
     4         if(grid.size() == 0) return 0;
     5         for(int i = 0; i < grid.size(); i ++)
     6         {
     7             for(int j = 0; j < grid[0].size(); j ++)
     8             {
     9                 int tmp = 0x3f3f3f3f;
    10                 if(i > 0) tmp = min(tmp, grid[i][j] + grid[i - 1][j]);
    11                 if(j > 0) tmp = min(tmp, grid[i][j] + grid[i][j - 1]);
    12                 grid[i][j] = tmp == 0x3f3f3f3f ? grid[i][j] : tmp;
    13             }
    14         }
    15         return grid[grid.size() - 1][grid[0].size() - 1];
    16     }
    17 };
    View Code

    Unique Paths II

     递推

     1 class Solution {
     2 public:
     3     int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {
     4         if(obstacleGrid.size() == 0) return 0;
     5         obstacleGrid[0][0] = obstacleGrid[0][0] != 1;
     6         for(int i = 0; i < obstacleGrid.size(); i ++)
     7             for(int j = 0; j < obstacleGrid[0].size(); j ++)
     8             {
     9                 if(i == 0 && j == 0) continue;
    10                 if(obstacleGrid[i][j] == 1) 
    11                 {
    12                     obstacleGrid[i][j] = 0;
    13                     continue;
    14                 }
    15                 if(i > 0) obstacleGrid[i][j] += obstacleGrid[i - 1][j];
    16                 if(j > 0) obstacleGrid[i][j] += obstacleGrid[i][j - 1];
    17             }
    18         return obstacleGrid[obstacleGrid.size() - 1][obstacleGrid[0].size() - 1];
    19     }
    20 };
    View Code

    Unique Paths

    这是当年学组合数时候的经典题型吧。

     1 class Solution {
     2 public:
     3     int COM(int a, int b)
     4     {
     5         b = min(b, a - b);
     6         int ret = 1, i, j;
     7         for(i = a, j = 1; i > a - b; i --)
     8         {
     9             ret *= i;
    10             for(; j <= b && ret % j == 0; j ++)
    11                 ret /= j;
    12         }
    13         return ret;
    14     }
    15     int uniquePaths(int m, int n) {
    16         return COM(m + n - 2, m - 1);
    17     }
    18 };
    View Code

    Rotate List

    因为k可能比长度大,需要求长度然后k对长度取模。那么就不要矫情地追求双指针一遍扫描了。

     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 *rotateRight(ListNode *head, int k) {
    12         if(head == NULL) return NULL;
    13         int cnt;
    14         ListNode *en, *p;
    15         for(cnt = 1, en = head; en->next != NULL; cnt ++, en = en->next);
    16         k %= cnt;
    17         for(p = head, cnt --; cnt != k; cnt --, p = p->next);
    18         en->next = head;
    19         en = p->next;
    20         p->next = NULL;
    21         return en;
    22     }
    23 };
    View Code

    Permutation Sequence

     一位一位算,每一位优先没使用过的较小的数字,而其后剩下的m个位置有 m! 种排列方法,用 k 减去,直到k不大于这个方法数,则这一位就是枚举到的这个数。

     1 class Solution {
     2 public:
     3     int permu[10];
     4     bool vis[10];
     5     string getPermutation(int n, int k) {
     6         permu[0] = 1;
     7         for(int i = 1; i < 10; i ++) permu[i] = permu[i - 1] * i;
     8         memset(vis, 0, sizeof(vis));
     9         string ans;
    10         for(int i = 1; i <= n; i ++)
    11         {
    12             for(int j = 1; j <= n; j ++)
    13             {
    14                 if(!vis[j])
    15                 {
    16                     if(k > permu[n - i]) k -= permu[n - i];
    17                     else {ans += '0' + j; vis[j] = true; break;}
    18                 }
    19             }
    20         }
    21         return ans;
    22     }
    23 };
    View Code

    Spiral Matrix II

    直接算每个位置的数是多少有木有很霸气

    先看当前位置之外有几个嵌套的正方形,再看当前位置在当前正方形四条边的第几条,求出坐标(x,y)位置的数。

     1 class Solution {
     2 public:
     3     vector<vector<int> > res;
     4     vector<int> nsq;
     5     int calnum(int i, int j, int n)
     6     {
     7         int num, tmp;
     8         tmp = min(min(i, j), min(n - 1 - i, n - 1 - j));
     9         num = nsq[tmp];
    10         if(i == tmp) return num + j - tmp + 1;
    11         if(n - j - 1 == tmp) return num + n - 2 * tmp + i - tmp;
    12         if(n - i - 1 == tmp) return num + 2 * (n - 2 * tmp) - 2 + n - j - tmp;
    13         return num + 3 * (n - 2 * tmp) - 3 + n - i - tmp;
    14     }
    15     vector<vector<int> > generateMatrix(int n) {
    16         nsq.push_back(0);
    17         for(int i = n; i > 0; i -= 2) nsq.push_back(4 * i - 4);
    18         for(int i = 1; i < nsq.size(); i ++) nsq[i] += nsq[i - 1];
    19         for(int i = 0; i < n; i ++)
    20         {
    21             vector<int> tmp;
    22             for(int j = 0; j < n; j ++)
    23             {
    24                 tmp.push_back(calnum(i, j, n));
    25             }
    26             res.push_back(tmp);
    27         }
    28         return res;
    29     }
    30 };
    View Code

    Length of Last Word 

     从后往前找。

    1 class Solution {
    2 public:
    3     int lengthOfLastWord(const char *s) {
    4         int i, j;
    5         for(i = strlen(s) - 1; i >= 0 && s[i] == ' '; i --);
    6         for(j = i - 1; j >= 0 && s[j] != ' '; j --);
    7         return i < 0 ? 0 : i - j;
    8     }
    9 };
    View Code

    Insert Interval

    end 比 newInterval 的 start 小的 intervals 直接插入,从 end 比 newInterval 的 start 大的 intervals 开始,到 start 比 newInterval 的 end 大的 intervals 结束,对这部分区间合并,再把之后的 intervals直接插入,特判 newInterval 最小和最大两种极端情况。

     1 /**
     2  * Definition for an interval.
     3  * struct Interval {
     4  *     int start;
     5  *     int end;
     6  *     Interval() : start(0), end(0) {}
     7  *     Interval(int s, int e) : start(s), end(e) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     vector<Interval> res;
    13     vector<Interval> insert(vector<Interval> &intervals, Interval newInterval) {
    14         if(intervals.size() == 0) {res.push_back(newInterval); return res;}
    15         int i, j;
    16         for(i = 0; i < intervals.size() && newInterval.start > intervals[i].end; i ++)
    17             res.push_back(intervals[i]);
    18         for(j = i; j < intervals.size() && newInterval.end >= intervals[j].start; j ++);
    19         if(j != 0 && i != intervals.size()) 
    20             res.push_back(Interval(min(intervals[i].start, newInterval.start),
    21                                 max(intervals[j - 1].end, newInterval.end)));
    22         else
    23             res.push_back(newInterval);
    24         for(; j < intervals.size(); j ++) res.push_back(intervals[j]);
    25         return res;
    26     }
    27 };
    View Code

    Merge Intervals

    先按start排个序,然后慢慢合并。。。

     1 /**
     2  * Definition for an interval.
     3  * struct Interval {
     4  *     int start;
     5  *     int end;
     6  *     Interval() : start(0), end(0) {}
     7  *     Interval(int s, int e) : start(s), end(e) {}
     8  * };
     9  */
    10 class Solution {
    11 public:
    12     vector<Interval> res;
    13     static bool cxompp(const Interval &a, const Interval &b)
    14     {return a.start < b.start;}
    15     vector<Interval> merge(vector<Interval> &intervals) {
    16         if(intervals.size() == 0) return res;
    17         sort(intervals.begin(), intervals.end(), cxompp);
    18         Interval last = intervals[0];
    19         for(int i = 1; i < intervals.size(); i ++)
    20         {
    21             if(last.end >= intervals[i].start)
    22                 last.end = max(last.end, intervals[i].end);
    23             else
    24                 res.push_back(last), last = intervals[i];
    25         }
    26         res.push_back(last);
    27         return res;
    28     }
    29 };
    View Code

    Jump Game

     维护最大可跳距离,每个位置都枚举一次。

     1 class Solution {
     2 public:
     3     bool canJump(int A[], int n) {
     4         if(n == 0) return false;
     5         int i, jumpdis;
     6         for(i = jumpdis = 0; i < n && jumpdis >= 0; i ++, jumpdis --)
     7             jumpdis = max(A[i], jumpdis);
     8         return i == n;
     9     }
    10 };
    View Code

    Spiral Matrix

     模拟转一遍吧。写了俩代码,差不多,处理拐弯的方式略有不同。

    代码一:

     1 class Solution {
     2 public:
     3     int dx[4] = {0, 1, 0, -1};
     4     int dy[4] = {1, 0, -1, 0};
     5     vector<int> res;
     6     bool JudgeValid(int x, int y, 
     7         vector<vector<bool> > &vis, vector<vector<int> > &matrix)
     8     {
     9         return x >= 0 && x < matrix.size() && 
    10             y >= 0 && y < matrix[0].size() && vis[x][y] == false;
    11     }
    12     vector<int> spiralOrder(vector<vector<int> > &matrix) {
    13         int dir, x, y, nx, ny;
    14         if(matrix.size() == 0) return res; 
    15         vector<vector<bool> > vis(matrix.size(), vector<bool>(matrix[0].size(), false));
    16         for(dir = x = y = 0; JudgeValid(x, y, vis, matrix); x = nx, y = ny)
    17         {
    18             res.push_back(matrix[x][y]);
    19             vis[x][y] = true;
    20             nx = x + dx[dir];
    21             ny = y + dy[dir];
    22             if(!JudgeValid(nx, ny, vis, matrix))
    23             {
    24                 dir = (dir + 1) % 4;
    25                 nx = x + dx[dir];
    26                 ny = y + dy[dir];
    27             }
    28         }
    29         return res;
    30     }
    31 };            
    View Code

    代码二:

     1 class Solution {
     2 public:
     3     int dx[4] = {0, 1, 0, -1};
     4     int dy[4] = {1, 0, -1, 0};
     5     vector<int> res;
     6     vector<int> spiralOrder(vector<vector<int> > &matrix) {
     7         int dir, x, y, nx, ny;
     8         int l, r, u, d;
     9         if(matrix.size() == 0) return res; 
    10         l = u = -1;
    11         r = matrix[0].size();
    12         d = matrix.size();
    13         for(dir = x = y = 0; res.size() < matrix.size() * matrix[0].size(); 
    14             x = nx, y = ny)
    15         {
    16             res.push_back(matrix[x][y]);
    17             nx = x + dx[dir];
    18             ny = y + dy[dir];
    19             if(nx == d || nx == u || ny == r || ny == l)
    20             {
    21                 dir = (dir + 1) % 4;
    22                 if(dir == 0) l ++, r --, d --;
    23                 else if(dir == 3) u ++;
    24                 nx = x + dx[dir];
    25                 ny = y + dy[dir];
    26             }
    27         }
    28         return res;
    29     }
    30 };
    View Code

    Maximum Subarray

     最大子串和,子串要求至少包含一个数字。

    一个变量 sum 表示当前求得的子串和,当 sum 小于0时,对后面的子串没有贡献,则把 sum 置零,中间处理一下要求至少包含一个数字的要求即可。

     1 class Solution {
     2 public:
     3     int maxSubArray(int A[], int n) {
     4         int ans = A[0], sum = 0;
     5         for(int i = 0; i < n; i ++)
     6         {
     7             sum += A[i];
     8             if(sum < 0) sum = 0, ans = max(ans, A[i]);
     9             else ans = max(ans, sum);
    10         }
    11         return ans;
    12     }
    13 };
    View Code

    N-Queens II

     题目没说 n 的取值范围,就不用 位运算 做标记了。

    老老实实开三个 bool 数组,一个标记纵列,另外两个标记两个斜列,一行一行DFS。

     1 class Solution {
     2 public:
     3     vector<bool> col, lc, rc;
     4     int ans;
     5     void DFS(int cur, int n)
     6     {
     7         if(cur == n)
     8         {
     9             ans ++;
    10             return;
    11         }
    12         for(int i = 0; i < n; i ++)
    13         {
    14             if(!col[i] && !lc[n - cur - 1 + i] && !rc[cur + i])
    15             {
    16                 col[i] = lc[n - cur - 1 + i] = rc[cur + i] = true;
    17                 DFS(cur + 1, n);
    18                 col[i] = lc[n - cur - 1 + i] = rc[cur + i] = false;
    19             }
    20         }
    21     }
    22     int totalNQueens(int n) {
    23         ans = 0;
    24         col.resize(n, 0);
    25         lc.resize(n << 1, 0);
    26         rc.resize(n << 1, 0);
    27         DFS(0, n);
    28         return ans;
    29     }
    30 };
    View Code

    N-Queens

    同上

     1 class Solution {
     2 public:
     3     vector<string> tmp;
     4     vector<vector<string> > res;
     5     vector<bool> col, lc, rc;
     6     void DFS(int cur, int n)
     7     {
     8         if(cur == n)
     9         {
    10             res.push_back(tmp);
    11             return;
    12         }
    13         string now(n, '.');
    14         for(int i = 0; i < n; i ++)
    15         {
    16             if(!col[i] && !lc[n - cur - 1 + i] && !rc[cur + i])
    17             {
    18                 col[i] = lc[n - cur - 1 + i] = rc[cur + i] = true;
    19                 now[i] = 'Q';
    20                 tmp.push_back(now);
    21                 DFS(cur + 1, n);
    22                 tmp.pop_back();
    23                 now[i] = '.';
    24                 col[i] = lc[n - cur - 1 + i] = rc[cur + i] = false;
    25             }
    26         }
    27     }
    28     vector<vector<string> > solveNQueens(int n) {
    29         col.resize(n, 0);
    30         lc.resize(n << 1, 0);
    31         rc.resize(n << 1, 0);
    32         DFS(0, n);
    33         return res;
    34     }
    35 };
    View Code

    Pow(x, n)

     很多人用特判错过了 n = -2147483648 这么优美的 trick,而不特判的话,似乎只能 long long 了。

    经典的快速幂,用二进制理解也好,用折半理解也好,网上很多资料。

     1 class Solution {
     2 public:
     3     double pow(double x, int n) {
     4         double res = 1;
     5         long long nn = n;
     6         if(nn < 0) x = 1 / x, nn = -nn;
     7         while(nn)
     8         {
     9             if(nn & 1) res *= x;
    10             x *= x;
    11             nn >>= 1;
    12         }
    13         return res;
    14     }
    15 };
    View Code

    Anagrams

    这概念以前没听过诶。。题也没看到样例,不知道以后会不会更新,网上查了才明白啥意思。

    调换单词字母顺序能一致的单词集合全放进答案。比如有tea, eat, aet,就都要放进答案,有cat, atc,就都要放进答案,而如果孤零零有个dog,没其他可和他一组的,那么就不放进答案。

    手写hash能更快些,但是题目没给数据范围,给hash数组定多大都没合理性,干脆用unordered_map好了。

     1 class Solution {
     2 public:
     3     vector<string> res;
     4     vector<string> anagrams(vector<string> &strs) {
     5         unordered_map<string, int> mp;
     6         for(int i = 0; i < strs.size(); i ++)
     7         {
     8             string tmp = strs[i];
     9             sort(tmp.begin(), tmp.end());
    10             if(!mp.count(tmp)) mp[tmp] = 0;
    11             else mp[tmp] ++;
    12         }
    13         for(int i = 0; i < strs.size(); i ++)
    14         {
    15             string tmp = strs[i];
    16             sort(tmp.begin(), tmp.end());
    17             if(mp.count(tmp) && mp[tmp] > 0) res.push_back(strs[i]);
    18         }
    19         return res;
    20     }
    21 };
    View Code

    Rotate Image

    四个一组,就地旋转。

     1 class Solution {
     2 public:
     3     void rotate(vector<vector<int> > &matrix) {
     4         if(matrix.size() == 0) return;
     5         int len = matrix.size();
     6         int lenlimi = len + 1 >> 1;
     7         for(int i = 0; i < lenlimi; i ++)
     8             for(int j = 0; j < (len & 1 ? lenlimi - 1 : lenlimi); j ++)
     9             {
    10                 int tmp = matrix[i][j];
    11                 matrix[i][j] = matrix[len - j - 1][i];
    12                 matrix[len - j - 1][i] = matrix[len - i - 1][len - j - 1];
    13                 matrix[len - i - 1][len - j - 1] = matrix[j][len - i - 1];
    14                 matrix[j][len - i - 1] = tmp;
    15             }
    16     }
    17 };
    View Code

    Permutations II

     有重复数字,把数字统计起来好了。因为题目没说数字大小,所以统计用了unordered_map。

    也可以把数组排序,DFS时跳过重复的数字。

     1 class Solution {
     2 public:
     3     unordered_map<int, int> mp;
     4     vector<int> tmp;
     5     vector<vector<int> > res;
     6     int numsize;
     7     void DFS(int cnt)
     8     {
     9         if(cnt == numsize)
    10         {
    11             res.push_back(tmp);
    12         }
    13         for(unordered_map<int, int>::iterator it = mp.begin(); it != mp.end(); it ++)
    14         {
    15             if(it->second != 0)
    16             {
    17                 tmp.push_back(it->first);
    18                 it->second --;
    19                 DFS(cnt + 1);
    20                 tmp.pop_back();
    21                 it->second ++;
    22             }
    23         }
    24     }
    25     vector<vector<int> > permute(vector<int> &num) {
    26         numsize = num.size();
    27         for(int i = 0; i < num.size(); i ++)
    28         {
    29             if(!mp.count(num[i])) mp[num[i]] = 1;
    30             else mp[num[i]] ++;
    31         }
    32         DFS(0);
    33         return res;
    34     }
    35 };
    View Code

    Permutations

    虽然题目没说有没有重复数字。。既然 Permutations II 说有了,那就当这个没有吧。

    传统DFS。

     1 class Solution {
     2 public:
     3     vector<vector<int> > res;
     4     void DFS(int cur, vector<int> &num)
     5     {
     6         if(cur == num.size())
     7         {
     8             res.push_back(num);
     9             return;
    10         }
    11         for(int i = cur; i < num.size(); i ++)
    12         {
    13             swap(num[cur], num[i]);
    14             DFS(cur + 1, num);
    15             swap(num[cur], num[i]);
    16         }
    17     }
    18     vector<vector<int> > permute(vector<int> &num) {
    19         DFS(0, num);
    20         return res;
    21     }
    22 };
    View Code

    Jump Game II

    维护一步最远到达的位置,到达这个位置之前的位置需要的步数都是一样的,到达这个位置的时候,下一步的最远位置已经更新完毕。

     1 class Solution {
     2 public:
     3     int jump(int A[], int n) {
     4         int nex = 0, pace = 0, far = 0;
     5         for(int i = 0; i <= nex && i < n - 1; i ++)
     6         {
     7             far = max(far, A[i] + i);
     8             if(i == nex)
     9             {
    10                 pace ++;
    11                 nex = far;
    12             }
    13         }
    14         return pace;
    15     }
    16 };
    View Code

    Wildcard Matching

    同步扫描两个字符串,每当 p 遇到 '*' ,记录s和p的当前扫描位置,当 s 与 p 不匹配时,跑扫描指针回到 '*' 后一个字符, s 扫描指针回到上次遇到 '*' 之后与 p 开始匹配位置的下一个位置。

     1 class Solution {
     2 public:
     3     bool isMatch(const char *s, const char *p) {
     4         int last_star = -1, last_s = -1, i, j;
     5         for(i = j = 0; s[i]; )
     6         {
     7             if(s[i] == p[j] || p[j] == '?') i ++, j ++;
     8             else if(p[j] == '*') last_star = ++ j, last_s = i;
     9             else if(last_star != -1) i = ++ last_s, j = last_star;
    10             else return false;
    11         }
    12         while(p[j] == '*') j ++;
    13         return !s[i] && !p[j];
    14     }
    15 };
    View Code

    Multiply Strings

     翻转num1和num2,大整数乘法,把结果再翻转。注意 int 和 char 的转换。

     1 class Solution {
     2 public:
     3     string multiply(string num1, string num2) {
     4         string ans(num1.length() + num2.length() + 1, 0);
     5         reverse(num1.begin(), num1.end());
     6         reverse(num2.begin(), num2.end());
     7         int cur = 0, i, j, k;
     8         for(i = 0; i < num1.length(); i ++)
     9         {
    10             for(j = 0; j < num2.length(); j ++)
    11             {
    12                 ans[i + j] += cur + (num1[i] - '0') * (num2[j] - '0');
    13                 cur = ans[i + j] / 10;
    14                 ans[i + j] %= 10;
    15             }
    16             for(k = i + j; cur; k ++)
    17             {
    18                 ans[k] += cur;
    19                 cur = ans[k] / 10;
    20                 ans[k] %= 10;
    21             }
    22         }
    23         for(k = ans.length() - 1; k > 0 && ans[k] == 0; k --);
    24         ans.resize(k + 1);
    25         for(int i = 0; i < ans.length(); i ++) ans[i] += '0';
    26         reverse(ans.begin(), ans.end());
    27         return ans;
    28     }
    29 };
    View Code

    Trapping Rain Water

     对于每个位置,取这个位置“左边最高的”和“右边最高的”的”较低者“,如果“较低者”比这个位置高,则这个位置存水高度为“较低者”减该位置高度。

     1 class Solution {
     2 public:
     3     int trap(int A[], int n) {
     4         vector<int> pre;
     5         int i, maxheight, ans;
     6         for(i = maxheight = 0; i < n; i ++)
     7         {
     8             maxheight = max(A[i], maxheight);
     9             pre.push_back(maxheight);
    10         }
    11         for(maxheight = ans = 0, i = n - 1; i > 0; i --)
    12         {
    13             maxheight = max(A[i], maxheight);
    14             ans += max(0, min(pre[i] - A[i], maxheight - A[i]));
    15         }
    16         return ans;
    17     }
    18 };
    View Code

    First Missing Positive

    题目要求时间O(n),空间O(1),经分析,不得不破坏原数组 A。

    方法一:

    剔除非整数,把原数组 A 当作存在标记,存在的数 x 则 A[x-1]取负数。

     1 class Solution {
     2 public:
     3     int firstMissingPositive(int A[], int n) {
     4         int i, j;
     5         for(i = j = 0; i < n; i ++)
     6             if(A[i] > 0) A[j ++] = A[i];
     7         for(i = 0; i < j; i ++)
     8             if(abs(A[i]) <= j) A[abs(A[i]) - 1] = -abs(A[abs(A[i]) - 1]);
     9         for(i = 0; i < j; i ++)
    10             if(A[i] > 0) return i + 1;
    11         return j + 1;
    12     }
    13 };
    View Code

    方法二:
    把出现的符合范围的数swap到下标和数对应的位置,再次遍历,数和下标不对应则是第一个没出现的数。注意处理有重复数字。

     1 class Solution {
     2 public:
     3     int firstMissingPositive(int A[], int n) {
     4         int i;
     5         for(i = 0; i < n; i ++)
     6             while(A[i] <= n && A[i] > 0 && A[i] != i + 1 && A[A[i] - 1] != A[i]) 
     7                 swap(A[i], A[A[i] - 1]);
     8         for(i = 0; i < n; i ++)
     9             if(A[i] != i + 1) return i + 1;
    10         return i + 1;
    11     }
    12 };
    View Code

    Combination Sum

    基础DFS

     1 class Solution {
     2 public:
     3     vector<int> tmp;
     4     vector<vector<int> > ans;
     5     void DFS(vector<int> &num, int ith, int now, int target)
     6     {
     7         if(now == target)
     8         {
     9             ans.push_back(tmp);
    10             return;
    11         }
    12         if(ith == num.size()) return;
    13         int cnt = 0;
    14         while(now <= target)
    15         {
    16             DFS(num, ith + 1, now, target);
    17             now += num[ith];
    18             cnt ++;
    19             tmp.push_back(num[ith]);
    20         }
    21         while(cnt --) tmp.pop_back();
    22     }
    23     vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
    24         sort(candidates.begin(), candidates.end());
    25         DFS(candidates, 0, 0, target);
    26         return ans;
    27     }
    28 };
    View Code

    Combination Sum II

    如果一个数没有被用,那么后面重复的这个数就别用,避免重复解。

     1 class Solution {
     2 public:
     3     vector<int> tmp;
     4     vector<vector<int> > ans;
     5     void DFS(vector<int> &num, int ith, int now, int target)
     6     {
     7         if(now == target)
     8         {
     9             ans.push_back(tmp);
    10             return;
    11         }
    12         if(ith == num.size()) return;
    13         int nex;
    14         for(nex = ith + 1; nex < num.size() && num[nex] == num[ith]; nex ++);
    15         DFS(num, nex, now, target);
    16         if(num[ith] + now <= target)
    17         {
    18             now += num[ith];
    19             tmp.push_back(num[ith]);
    20             DFS(num, ith + 1, now, target);
    21             tmp.pop_back();
    22         }
    23     }
    24     vector<vector<int> > combinationSum2(vector<int> &num, int target) {
    25         sort(num.begin(), num.end());
    26         DFS(num, 0, 0, target);
    27         return ans;
    28     }
    29 };
    View Code

    Count and Say

    直接模拟,递推。

     1 class Solution {
     2 public:
     3     string countAndSay(int n) {
     4         string f[2];
     5         f[0] = "1";
     6         for(int i = 1; i < n; i ++)
     7         {
     8             f[i & 1].clear();
     9             for(int j = 0; j < f[i & 1 ^ 1].length();)
    10             {
    11                 int cnt;
    12                 char x = f[i & 1 ^ 1][j];
    13                 for(cnt = 0; j < f[i & 1 ^ 1].length() && f[i & 1 ^ 1][j] == x; cnt ++, j ++);
    14                 f[i & 1] += '0' + cnt;
    15                 f[i & 1] += x;
    16             }
    17         }
    18         return f[n & 1 ^ 1];
    19     }
    20 };
    View Code

    Sudoku Solver

    这道题考察回溯和数独结果的判断。ACM做过,就直接拿dancing links代码了,4ms。

    关于dancing links,对于面试题来说变态了些,应该不至于考察。

      1 class Solution {
      2 public:
      3     int rw[10], cl[10], in[10], RW[81], CL[81], IN[81], goal;
      4     char buf[100];
      5     void Mark(int i, int num)
      6     {
      7         rw[RW[i]] ^= 1 << num;
      8         cl[CL[i]] ^= 1 << num;
      9         in[IN[i]] ^= 1 << num;
     10     }
     11     void init()
     12     {
     13         int i;
     14         for(i = 0; i < 10; ++ i)
     15             cl[i] = rw[i] = in[i] = 0;
     16         for(i = goal = 0; buf[i]; ++ i)
     17             goal += buf[i] == '.';
     18         for(i = 0; i < 81; ++ i)
     19         {
     20             RW[i] = i / 9, CL[i] = i % 9, IN[i] = i / 3 % 3 + i / 27 * 3;
     21             if(buf[i] != '.')
     22                 Mark(i, buf[i] - '1');
     23         }
     24     }
     25     inline int Judge(int i, int num)
     26     {return ~(rw[RW[i]] | cl[CL[i]] | in[IN[i]]) & (1 << num);}
     27     int Oper(int sx, int k, int cur)
     28     {
     29         Mark(sx, k), buf[sx] = k + '1';
     30         if(dfs(cur + 1)) return 1;
     31         Mark(sx, k), buf[sx] = '.';
     32         return 0;
     33     }
     34     int JudgeRWCLIN(int cur)
     35     {
     36         int i, j, k, x, cnt, sx;
     37         for(i = 0; i < 9; ++ i)
     38             for(k = 0; k < 9; ++ k)
     39             {
     40                 if(~rw[i] & (1 << k))
     41                 {
     42                     for(j = cnt = 0; j < 9; ++ j)
     43                     {
     44                         x = i * 9 + j;
     45                         if(buf[x] == '.' && Judge(x, k)) ++ cnt, sx = x;
     46                     }
     47                     if(cnt == 0) return 0;
     48                     else if(cnt == 1)
     49                         return Oper(sx, k, cur);
     50                 }
     51                 if(~cl[i] & (1 << k))
     52                 {
     53                     for(j = cnt = 0; j < 9; ++ j)
     54                     {
     55                         x = j * 9 + i;
     56                         if(buf[x] == '.' && Judge(x, k)) ++ cnt, sx = x;
     57                     }
     58                     if(cnt == 0) return 0;
     59                     else if(cnt == 1)
     60                         return Oper(sx, k, cur);
     61                 }
     62                 if(~in[i] & (1 << k))
     63                 {
     64                     for(j = cnt = 0; j < 9; ++ j)
     65                     {
     66                         x = i / 3 * 27 + j / 3 * 9 + i % 3 * 3 + j % 3;
     67                         if(buf[x] == '.' && Judge(x, k)) ++ cnt, sx = x;
     68                     }
     69                     if(cnt == 0) return 0;
     70                     else if(cnt == 1)
     71                         return Oper(sx, k, cur);
     72                 }
     73             }
     74         return 2;
     75     }
     76                         
     77         
     78     bool dfs(int cur)
     79     {
     80         int i, j, num, cnt;
     81         if(cur == goal) return true;
     82         for(i = 0; i < 81; ++ i)
     83             if(buf[i] == '.')
     84             {
     85                 for(j = cnt = 0; j < 9; ++ j)
     86                     if(Judge(i, j)) ++ cnt, num = j;
     87                 if(cnt == 0) return false;
     88                 if(cnt == 1)
     89                         return Oper(i, num, cur);
     90             }
     91         if((num = JudgeRWCLIN(cur)) == 0) return false;
     92         else if(num == 1) return true;
     93         for(i = 0; i < 81; ++ i)
     94             if(buf[i] == '.')
     95             {
     96                 for(j = 0; j < 9; ++ j)
     97                     if(Judge(i, j))
     98                     {
     99                         Mark(i, j), buf[i] = j + '1';
    100                         if(dfs(cur + 1)) return true;
    101                         Mark(i, j), buf[i] = '.';
    102                     }
    103             }
    104         return false;
    105     }
    106     void solveSudoku(vector<vector<char> > &board) {
    107         int site = 0;
    108         for(int i = 0; i < 9; i ++)
    109             for(int j = 0; j < 9; j ++)
    110                 buf[site ++] = board[i][j];
    111         init();
    112         dfs(0);
    113         site = 0;
    114         for(int i = 0; i < 9; i ++)
    115             for(int j = 0; j < 9; j ++)
    116                 board[i][j] = buf[site ++];
    117     }
    118 };
    View Code

    Valid Sudoku

    行列九宫格都判断一下。

     1 class Solution {
     2 public:
     3     bool isValidSudoku(vector<vector<char> > &board) {
     4         bool flag[3][9][9];
     5         memset(flag, false, sizeof(flag));
     6         for(int i = 0; i < 9; i ++)
     7         {
     8             for(int j = 0; j < 9; j ++)
     9             {
    10                 if(board[i][j] != '.')
    11                 {
    12                     int x = board[i][j] - '1';
    13                     if(flag[0][i][x] == true) return false;
    14                     flag[0][i][x] = true;
    15                     if(flag[1][j][x] == true) return false;
    16                     flag[1][j][x] = true;
    17                     if(flag[2][i / 3 * 3 + j / 3][x] == true) return false;
    18                     flag[2][i / 3 * 3 + j / 3][x] = true;
    19                 }
    20             }
    21         }
    22         return true;
    23     }
    24 };
    View Code

    Search Insert Position

     二分

     1 class Solution {
     2 public:
     3     int searchInsert(int A[], int n, int target) {
     4         int left, right, mid;
     5         for(left = 0, right = n; left < right; )
     6         {
     7             mid = left + right >> 1;
     8             if(A[mid] == target) return mid;
     9             if(A[mid] > target) right = mid;
    10             else left = mid + 1;
    11         }
    12         return left;
    13     }
    14 };
    View Code

    Search for a Range

    二分,容易错。可以用lower_bound和upper_bound。

    手工代码:

     1 class Solution {
     2 public:
     3     vector<int> searchRange(int A[], int n, int target) {
     4         int left, right, mid, l, r;
     5         for(left = 0, right = n; left < right; )
     6         {
     7             mid = left + right >> 1;
     8             if(A[mid] >= target) right = mid;
     9             else left = mid + 1;
    10         }
    11         l = left;
    12         for(left = 0, right = n; left < right; )
    13         {
    14             mid = left + right >> 1;
    15             if(A[mid] > target) right = mid;
    16             else left = mid + 1;
    17         }
    18         r = left - 1;
    19         if(l >= n || A[l] != target) return vector<int>(2, -1);
    20         vector<int> ans = {l, r};
    21         return ans;
    22     }
    23 };
    View Code

    STL:

     1 class Solution {
     2 public:
     3     vector<int> searchRange(int A[], int n, int target) {
     4         int l = lower_bound(A, A + n, target) - A;
     5         int r = upper_bound(A, A + n, target) - A;
     6         if(l == n || A[l] != target) return vector<int>(2, -1);
     7         vector<int> ans = {l, r - 1};
     8         return ans;
     9     }
    10 };
    View Code

    Search in Rotated Sorted Array

    还是二分,但是要判断一下 mid 在哪部分里。

     1 class Solution {
     2 public:
     3     int search(int A[], int n, int target) {
     4         int left = 0, right = n - 1, mid;
     5         while(left < right)
     6         {
     7             mid = left + right >> 1;
     8             if(A[mid] == target) return mid;
     9             if(A[mid] >= A[left])
    10             {
    11                 if(target < A[mid] && A[left] <= target) right = mid;
    12                 else left = mid + 1;
    13             }
    14             else
    15             {
    16                 if(target <= A[right] && A[mid] < target) left = mid + 1;
    17                 else right = mid;
    18             }
    19         }
    20         return A[left] == target ? left : -1;
    21     }
    22 };
    View Code

    Longest Valid Parentheses

    这道题时间限制在O(n),用一个 stack 实现括号配对+统计, 为了方便实现,写成数组的形式。

    对不同深度的括号配对统计个数,一层配对成功把该层统计结果加给上一层,这一层清空。

     1 class Solution {
     2 public:
     3     int longestValidParentheses(string s) {
     4         vector<int> cnt(1, 0);
     5         int i, ans;
     6         for(i = ans = 0; i < s.length(); i ++)
     7         {
     8             if(s[i] == '(')
     9                 cnt.push_back(0);
    10             else
    11             {
    12                 if(cnt.size() > 1)
    13                 {
    14                     cnt[cnt.size() - 2] += *cnt.rbegin() + 2;
    15                     cnt.pop_back();
    16                     ans = max(ans, *cnt.rbegin());
    17                 }
    18                 else
    19                     cnt[0] = 0;
    20             }
    21         }
    22         return ans;
    23     }
    24 };
    View Code

    Next Permutation

    从后往前找到第一个非降序的 num[i],再重新从后往前找到第一个比 num[i] 大的,swap(num[i], num[j]),再把 i 之后的排序。

     1 class Solution {
     2 public:
     3     void nextPermutation(vector<int> &num) {
     4         int i, j;
     5         for(i = num.size() - 2; i >= 0 && num[i] >= num[i + 1]; i --);
     6         for(j = num.size() - 1; j > i && num[j] <= num[i]; j --);
     7         if(i < j)
     8         {
     9             swap(num[i], num[j]);
    10             sort(num.begin() + i + 1, num.end());
    11         }
    12         else
    13             reverse(num.begin(), num.end());
    14     }
    15 };
    View Code

    Substring with Concatenation of All Words

    直观的方法是枚举起点,判断这个起点下的子串是否合法,O(S.length()*L.size())。

    其实可以把 S 分成 L[0].length() 个序列,每个序列都是元素间相隔 L[0].length() 的“string开头”,这些序列互不相干。

    如下表,假设 L[0].length()=4,第一行数字为分组组号,第二行数字表示 S 的序号。

    (0) (1) (2) (3) (0) (1) (2) (3) (0) (1) (2) (3) (0) (1) (2) (3) (0) (1) (2) (3) (0)
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

    对每个序列,用单调队列的思路来处理,一个一个子串入队,当包含了 L 中所有 string 的时候,保存答案。当新元素入队时超出统计允许时——即 L 中有 3 个 "str", 而这时候遇到第 4 个——则开始出队,一直出到队列里不足 3 个 "str",然后继续。

    这样复杂度为O(L[0].length() * S.length() / L[0].length()) = O(S.length())。目前提交结果是180ms。

     1 class Solution {
     2 public:
     3     vector<int> findSubstring(string S, vector<string> &L) {
     4         vector<int> ans;
     5         if(L.size() == 0) return ans;
     6         unordered_map<string, int> mp, sum;
     7         int llen = L[0].length(), i, front, rear;
     8         for(int i = 0; i < L.size(); i ++)
     9         {
    10             if(!mp.count(L[i])) mp[L[i]] = 1;
    11             else mp[L[i]] ++;
    12         }
    13         for(i = 0; i < llen; i ++)
    14         {
    15             sum = mp;
    16             int cnt = 0;
    17             for(front = rear = i; front + llen <= S.length(); front += llen)
    18             {
    19                 string tmp = S.substr(front, llen);
    20                 if(sum.count(tmp))
    21                 {
    22                     if(sum[tmp] > 0)
    23                     {
    24                         sum[tmp] --;
    25                         cnt ++;
    26                         if(cnt == L.size())
    27                         {
    28                             ans.push_back(rear);
    29                         }
    30                     }
    31                     else
    32                     {
    33                         while(sum[tmp] == 0)
    34                         {
    35                             string ntmp = S.substr(rear, llen);
    36                             sum[ntmp] ++;
    37                             cnt --;
    38                             rear += llen;
    39                         }
    40                         sum[tmp] --;
    41                         cnt ++;
    42                         if(cnt == L.size())
    43                         {
    44                             ans.push_back(rear);
    45                         }
    46                     }
    47                 }
    48                 else
    49                 {
    50                     while(rear < front)
    51                     {
    52                         string ntmp = S.substr(rear, llen);
    53                         sum[ntmp] ++;
    54                         cnt --;
    55                         rear += llen;
    56                     }
    57                     rear += llen;
    58                     cnt = 0;
    59                 }
    60             }
    61         }
    62         return ans;
    63     }
    64 };
    View Code

    Divide Two Integers

    假设 dividend 与 divisor 正负一致, divisor^(2^n) 为最接近 dividend 的 divisor 的幂,那么令 newdividend = dividend - divisor^(2^n),ans = ans + 2^n,问题就更新为 newdividend 除以 divisor,如此迭代。用 divisor^(2^n) 是因为 divisor 不停地辗转加自己就可以得到了。

    有 -2147483648 这样的极限数据,因为 int 范围是 -2147483648~+2147483647,发现负数比正数范围“多1”,干脆把所有数都转成负数算,这样就避免用 long long 了。最后考察一下flag。

    (如果转成正数的话,int 的 -(-2147483648)还是 -2147483648。。)

     1 class Solution {
     2 public:
     3     int divide(int dividend, int divisor) {
     4         bool flag = false;
     5         if(divisor > 0) divisor = -divisor, flag ^= true;
     6         if(dividend > 0) dividend = -dividend, flag ^= true;
     7         int ans = 0, res = divisor, ex = 1;
     8         if(divisor < dividend) return 0;
     9         while(res >= dividend - res)
    10         {
    11             res += res;
    12             ex += ex;
    13         }
    14         while(res <= divisor && dividend)
    15         {
    16             if(res >= dividend)
    17             {
    18                 dividend -= res;
    19                 ans += ex;
    20             }
    21             res >>= 1;
    22             ex >>= 1;
    23         }
    24         return flag ? -ans : ans;
    25     }
    26 };
    View Code

    Implement strStr()

     KMP。

     1 class Solution {
     2 public:
     3     char *strStr(char *haystack, char *needle) {
     4         int hlen = (int)strlen(haystack), nlen = (int)strlen(needle);
     5         if(nlen == 0) return haystack;
     6         vector<int> next(nlen + 1);
     7         next[0] = -1;
     8         for(int i = 0, j = -1; i < nlen;)
     9         {
    10             if(j == -1 || needle[i] == needle[j])
    11             {
    12                 i ++, j ++;
    13                 if(needle[i] != needle[j]) next[i] = j;
    14                 else next[i] = next[j];
    15             }
    16             else j = next[j];
    17         }
    18         for(int i = 0, j = 0; i < hlen;)
    19         {
    20             if(j == -1 || haystack[i] == needle[j])
    21                 i ++, j ++;
    22             else j = next[j];
    23             if(j == nlen) return haystack + i - j;
    24         }
    25         return NULL;
    26     }
    27 };
    View Code

    Remove Element

    两个游标 i, j 异步挪动,把不等于给定值的数往前挪。

    1 class Solution {
    2 public:
    3     int removeElement(int A[], int n, int elem) {
    4         int i, j;
    5         for(i = j = 0; i < n; i ++)
    6             if(A[i] != elem) A[j ++] = A[i];
    7         return j;
    8     }
    9 };
    View Code

    Remove Duplicates from Sorted Array

    两个游标 i, j 异步挪动,不重复值往前挪。

    1 class Solution {
    2 public:
    3     int removeDuplicates(int A[], int n) {
    4         int i, j;
    5         for(i = j = 1; i < n; i ++)
    6             if(A[i] != A[i - 1]) A[j ++] = A[i];
    7         return n ? j : 0;
    8     }
    9 };
    View Code

    Reverse Nodes in k-Group

    用头插法来做的,顺序插入到首节点之后,就反转了。每 k 个节点处理之后,把首节指针点移动到下 k 个的开头。最后面不足 k 个的话,再反转回来。

     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     int Reverse(ListNode *&pre, ListNode *&p, int k)
    12     {
    13         int i;
    14         ListNode *nex, *tmp;
    15         for(i = 1; p != NULL; i ++, p = tmp)
    16         {
    17             if(i == 1) nex = p;
    18             tmp = p->next;
    19             p->next = pre->next;
    20             pre->next = p;
    21             if(i == k) i = 0, pre = nex;
    22         }
    23         nex->next = NULL;
    24         return i;
    25     }
    26     ListNode *reverseKGroup(ListNode *head, int k) {
    27         if(head == NULL) return NULL;
    28         ListNode *tmphead = new ListNode(0), *pre = tmphead, *p = head;
    29         tmphead->next = head;
    30         if(Reverse(pre, p, k) != 1)
    31         {
    32             p = pre->next;
    33             Reverse(pre, p, k);
    34         }
    35         return tmphead->next;
    36     }
    37 };
    View Code

    Swap Nodes in Pairs

    Reverse Nodes in k-Group的简化版。

     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 *swapPairs(ListNode *head) {
    12         if(head == NULL) return NULL;
    13         ListNode *tmphead = new ListNode(0), *pre = tmphead, *p = head, *tmp, *nex;
    14         tmphead->next = head;
    15         for(int i = 0; p != NULL; i ++, p = tmp)
    16         {
    17             if(i & 1 ^ 1) nex = p;
    18             tmp = p->next;
    19             p->next = pre->next;
    20             pre->next = p;
    21             if(i & 1) pre = nex;
    22         }
    23         nex->next = NULL;
    24         return tmphead->next;
    25     }
    26 };
    View Code

    Merge k Sorted Lists

    一个堆(这里用了优先级队列),把所有 list 的首元素放堆里,O(logn)取得最小值插入新队列,异步推进。

     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     struct comp
    12     {
    13         bool operator()(ListNode *a,ListNode *b)
    14         {return a->val > b->val;}
    15     };
    16     ListNode *mergeKLists(vector<ListNode *> &lists) {
    17         ListNode *tmphead = new ListNode(0), *p = tmphead;
    18         priority_queue<ListNode*, vector<ListNode*>, comp> q;
    19         for(int i = 0; i < lists.size(); i ++)
    20             if(lists[i] != NULL) q.push(lists[i]);
    21         while(!q.empty())
    22         {
    23             p->next = q.top();
    24             p = p->next;
    25             q.pop();
    26             if(p ->next != NULL) q.push(p->next);
    27         }
    28         return tmphead->next;
    29     }
    30 };
    View Code

    Generate Parentheses

    DFS,保持当前右括号不多于左括号。

     1 class Solution {
     2 public:
     3     string tmp;
     4     vector<string> ans;
     5     void DFS(int left, int right, int n)
     6     {
     7         if(left == right && left == n)
     8         {
     9             ans.push_back(tmp);
    10             return;
    11         }
    12         if(left < n)
    13         {
    14             tmp[left + right] = '(';
    15             DFS(left + 1, right, n);
    16         }
    17         if(right < left)
    18         {
    19             tmp[left + right] = ')';
    20             DFS(left, right + 1, n);
    21         }
    22     }
    23     vector<string> generateParenthesis(int n) {
    24         tmp.resize(n << 1);
    25         DFS(0, 0, n);
    26         return ans;
    27     }
    28 };
    View Code

    Valid Parentheses

    用栈配对。

     1 class Solution {
     2 public:
     3     bool isValid(string s) {
     4         stack<char> st;
     5         for(int i = 0; i < s.length(); i ++)
     6         {
     7             switch(s[i])
     8             {
     9                 case '(': st.push('('); break;
    10                 case '[': st.push('['); break;
    11                 case '{': st.push('{'); break;
    12                 case ')':
    13                     if(st.empty() || st.top() != '(') return false;
    14                     st.pop(); break;
    15                 case ']':
    16                     if(st.empty() || st.top() != '[') return false;
    17                     st.pop(); break;
    18                 case '}':
    19                     if(st.empty() || st.top() != '{') return false;
    20                     st.pop(); break;
    21                     
    22             }
    23         }
    24         return st.empty();
    25     }
    26 };
    View Code

    Remove Nth Node From End of List

    两个指针相隔 n 距离,前面的指针到了末尾,后面的指针就是删除的位置。

     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 *removeNthFromEnd(ListNode *head, int n) {
    12         ListNode *pre, *slow, *quick;
    13         ListNode *newhead = new ListNode(0);
    14         newhead->next = head;
    15         int i = 0;
    16         for(pre = slow = quick = newhead; quick != NULL; i ++)
    17         {
    18             pre = slow;
    19             if(i >= n) slow = slow->next;
    20             quick = quick->next;
    21         }
    22         pre->next = slow->next;
    23         free(slow);
    24         return newhead->next;
    25     }
    26 };
    View Code

    Letter Combinations of a Phone Number

    基础DFS。

     1 class Solution {
     2 public:
     3     const vector<string> v = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
     4     vector<string> ans;
     5     string tmp;
     6     void DFS(int cur, string d)
     7     {
     8         if(cur == d.length())
     9         {
    10             ans.push_back(tmp);
    11             return;
    12         }
    13         for(int i = 0; i < v[d[cur] - '0'].length(); i ++)
    14         {
    15             tmp[cur] = v[d[cur] - '0'][i];
    16             DFS(cur + 1, d);
    17         }
    18     }
    19     vector<string> letterCombinations(string digits) {
    20         tmp.resize(digits.length());
    21         DFS(0, digits);
    22         return ans;
    23     }
    24 };
    View Code

    4Sum

    尝试了O(n^2)的,但是应该常数很大吧,超时了。就是哈希存两两的和,然后通过查哈希表找到 两两+两两,要判断数字重复情况。这题数据量挺大的,O(n^3)如果用不太好的方式实现的话也会超。

    O(n^3)方法:先对num排序,然后从两头枚举两个数,O(n^2),后两个数在前两个数之间的两端开始,和小了左边的往右,和大了右边的往左调整,O(n),总共O(n^3)。

     1 class Solution {
     2 public:
     3     vector<vector<int> > ans;
     4     vector<vector<int> > fourSum(vector<int> &num, int target) {
     5         if(num.size() < 4) return ans;
     6         sort(num.begin(), num.end());
     7         for(int left = 0; left < num.size() - 3;)
     8         {
     9             for(int right = num.size() - 1; right > left + 2;)
    10             {
    11                 int ml = left + 1, mr = right - 1;
    12                 while(ml < mr)
    13                 {
    14                     int tmpsum = num[left] + num[right] + num[ml] + num[mr];
    15                     if(tmpsum > target) mr --;
    16                     else if(tmpsum < target) ml ++;
    17                     else
    18                     {
    19                         vector<int> tmp = {num[left], num[ml], num[mr], num[right]};
    20                         ans.push_back(tmp);
    21                         ml ++;
    22                         mr --;
    23                     }
    24                     for(; ml != left + 1 && ml < mr && num[ml] == num[ml - 1]; ml ++);
    25                     for(; mr != right - 1 && ml < mr && num[mr] == num[mr + 1]; mr --);
    26                 }
    27                 for(right --; right > left + 2 && num[right] == num[right + 1]; right --);
    28             }
    29             for(left ++; left < num.size() - 3 && num[left] == num[left - 1]; left ++);
    30         }
    31         return ans;
    32     }
    33 };
    View Code

    3Sum Closest

    O(n^2),先排序,枚举第一个数,后两个数一个在第一个数后边一个开始,一个从 末尾开始,和4Sum类似调整。

     1 class Solution {
     2 public:
     3     int threeSumClosest(vector<int> &num, int target) {
     4         bool findans = false;
     5         int ans;
     6         sort(num.begin(), num.end());
     7         for(int i = 0; i < num.size(); i ++)
     8         {
     9             for(int left = i + 1, right = num.size() - 1; left < right;)
    10             {
    11                 int tmpsum = num[i] + num[left] + num[right];
    12                 if(tmpsum > target) right --;
    13                 else if(tmpsum < target) left ++;
    14                 else return tmpsum;
    15                 if(!findans || abs(tmpsum - target) < abs(ans - target))
    16                     ans = tmpsum, findans = true;
    17             }
    18         }
    19         return ans;
    20     }
    21 };
    View Code

    3Sum

    同上。

     1 class Solution {
     2 public:
     3     vector<vector<int> > ans;
     4     vector<vector<int> > threeSum(vector<int> &num) {
     5         if(num.size() < 3) return ans;
     6         sort(num.begin(), num.end());
     7         for(int i = 0; i < num.size();)
     8         {
     9             for(int left = i + 1, right = num.size() - 1; left <right;)
    10             {
    11                 int tmpsum = num[i] + num[left] + num[right];
    12                 if(tmpsum < 0) left ++;
    13                 else if(tmpsum > 0) right --;
    14                 else
    15                 {
    16                     vector<int> tmp = {num[i], num[left], num[right]};
    17                     ans.push_back(tmp);
    18                     left ++;
    19                     right --;
    20                 }
    21                 for(; left != i + 1 && left < right && num[left] == num[left - 1]; left ++);
    22                 for(; right != num.size() - 1 && left < right && num[right] == num[right + 1]; right --);
    23             }
    24             for(i ++; i < num.size() && num[i] == num[i - 1]; i ++);
    25         }
    26         return ans;
    27     }
    28 };
    View Code

    Longest Common Prefix

     一个一个扫

     1 class Solution {
     2 public:
     3     string ans;
     4     string longestCommonPrefix(vector<string> &strs) {
     5         if(strs.size() == 0) return ans;
     6         if(strs.size() == 1) return strs[0];
     7         for(int j = 0; ; j ++)
     8         {
     9             for(int i = 1; i < strs.size(); i ++)
    10                 if(strs[i].size() == j || strs[i][j] != strs[i - 1][j]) return ans;
    11             ans += strs[0][j];
    12         }
    13         return ans;
    14     }
    15 };
    View Code

    Roman to Integer

    各有各的方法,重点是记录“上一个”数比“这个”数大或小,来确定谁减谁。基本是右结合的,所以从后往前扫好处理些。

    class Solution {
    public:
        int ro[128];
        int romanToInt(string s) {
            ro['I'] = 1;
            ro['V'] = 5;
            ro['X'] = 10;
            ro['L'] = 50;
            ro['C'] = 100;
            ro['D'] = 500;
            ro['M'] = 1000;
            int ans = -1, last;
            for(int i = s.length() - 1; i >= 0; i --)
            {
                if(ans == -1) ans = ro[s[i]];
                else
                {
                    if(last > ro[s[i]]) ans -= ro[s[i]];
                    else ans += ro[s[i]];
                }
                last = ro[s[i]];
            }
            return ans;
        }
    };
    View Code

    Integer to Roman

    每个十进制位格式是一样的,只是字母替换一下。

     1 class Solution {
     2 public:
     3     vector<string> table = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
     4     string ro = "IVXLCDM";
     5     char convert(char x, int i)
     6     {
     7         if(x == 'I') return ro[i];
     8         if(x == 'V') return ro[i + 1];
     9         if(x == 'X') return ro[i + 2];
    10     }
    11     string intToRoman(int num) {
    12         string ans;
    13         for(int i = 0; num; i += 2, num /= 10)
    14         {
    15             int x = num % 10;
    16             string tmp = table[x];
    17             for(int j = 0; j < tmp.size(); j ++)
    18                 tmp[j] = convert(tmp[j], i);
    19             ans = tmp + ans;
    20         }
    21         return ans;
    22     }
    23 };
    View Code

    Container With Most Water

    从两端开始枚举,较高的挡板往中间枚举的话一定无法得到更优解,故反复从较低挡板向中间枚举,O(n)。

     1 class Solution {
     2 public:
     3     int maxArea(vector<int> &height) {
     4         int left = 0, right = height.size() - 1, ans = -1;
     5         while(left < right)
     6         {
     7             ans = max(ans, min(height[left], height[right]) * (right - left));
     8             if(height[left] < height[right]) left ++;
     9             else right --;
    10         }
    11         return ans;
    12     }
    13 };
    View Code

    Regular Expression Matching

    每遇到一个 '*' ,问题都会出现分枝,需要用到栈或者递归。

    没有 '*' 的情况好处理,遇到 '*' 的时候,穷举所有匹配长度。

     1 class Solution {
     2 public:
     3     bool isMatch(const char *s, const char *p) {
     4         if(*p == 0) return *s == 0;
     5         if(*(p + 1) != '*')
     6         {
     7             if(*s && (*s == *p || *p == '.'))
     8                return isMatch(s + 1, p + 1);
     9             return false;
    10         }
    11         else
    12         {
    13             for(; *s && (*s == *p || *p == '.'); s ++)
    14                 if(isMatch(s, p + 2)) return true;
    15             return isMatch(s, p + 2);
    16         }
    17     }
    18 };
    View Code

    Palindrome Number

    首先处理负数的trick。然后主要思路就是通过 while(...) a = a * 10 + x % 10; 来将 x 翻转。

    但是注意到 x 很大的时候,翻转的 x 会超出 int 范围,也许会刚好成为另一个和 a 得出的数相等的正数,所以不能完全翻转后判断,而可以在翻转恰好一半的时候判断。

     1 class Solution {
     2 public:
     3     bool isPalindrome(int x) {
     4         if(x < 0) return false;
     5         if(x == 0) return true;
     6         int a = 0, b = x, cnt = 1;
     7         while(x /= 10) cnt ++;
     8         for(; b && cnt >= 0; b /= 10, cnt -= 2) 
     9         {
    10             if(cnt == 1) return a == b / 10;
    11             else if(cnt == 0) return a == b;
    12             a = a * 10 + b % 10;
    13         }
    14         return false;
    15     }
    16 };
    View Code

    String to Integer (atoi)

    任何类似多符号、符号数字间有空格的小问题都直接输出 0,这就好办了。处理越界用 long long。

     1 class Solution {
     2 public:
     3     int atoi(const char *str) {
     4         long long ans = 0;
     5         bool flag = false;
     6         for(; *str == ' '; str ++);
     7         if(*str == '+') str ++;
     8         else if(*str == '-') flag = true, str ++;
     9         for(; isdigit(*str); str ++)
    10         {
    11             ans = ans * 10 + *str - '0';
    12             if((flag ? -ans : ans) > INT_MAX) return INT_MAX;
    13             else if((flag ? -ans : ans) < INT_MIN) return INT_MIN;
    14         }
    15         return (int)(flag ? -ans : ans);
    16     }
    17 };
    View Code

    Reverse Integer

    还是关于越界的讨论,不过这道题本身没有设置处理方式,重点在于面试时的交流。

    1 class Solution {
    2 public:
    3     int reverse(int x) {
    4         int a = 0;
    5         for( int b = x >= 0 ? x : -x; b; b /= 10)
    6             a = a * 10 + b % 10;
    7         return x >= 0 ? a : -a;
    8     }
    9 };
    View Code

    ZigZag Conversion

    题意的 "z" 字形指一列nRows个,然后斜着往右上一格一个回到第一行,然后再一列nRows个。比如nRows=5,如下:

    1       9       17       25    
    2     8 10     16 18     24 26    
    3   7   11   15   19   23   27  
    4 6     12 14     20 22     28 30  
    5       13       21       29    

    每行字母在原字符串中的间隔是有规律的,虽然两层for循环,但是s中每个字母只访问了一次,O(n)。

     1 class Solution {
     2 public:
     3     string convert(string s, int nRows) {
     4         if(nRows == 1) return s;
     5         string ans;
     6         int a = (nRows << 1) - 2, b = 0;
     7         for(int i = 0; i < nRows; i ++, a -= 2, b += 2)
     8         {
     9             bool flag = false;
    10             for(int j = i; j < s.length(); 
    11                     j += flag ? (b ? b : a) : (a ? a : b), flag ^= 1)
    12                 ans += s[j];
    13         }
    14         return ans;
    15     }
    16 };
    View Code

    Longest Palindromic Substring

    网上O(n)的方法是厉害啊。。。简单解释如下:

    1、预处理字符串,前后加“哨兵”字符比如 '!',每个字母旁边加辅助字符比如'#',这样例如字符串 s = "ababbcbb" 就变成 tmp = "!#a#b#a#b#b#c#b#b#!"。这样的好处是不用讨论回文串长度的奇偶。

    2、对转化后的串,维护一个 center 和一个 reach,center 是当前已发现的 reach 最远的回文串中心位置,reach 是这个回文串最右端的位置,center和reach可初始化为 1,即第一个'#'的位置。

    3、维护一个数组 vector<int> r(tmp.length()),r[i] 表示 i 位置为中心的回文串半径。

    4、在考察位置 i 的时候,所有 j < i 的 r[j] 都是已知的子问题。如果 i 在 reach 的左边,则 i 包含在以 center 为中心的回文串中,那么可以想到,如果和 i 关于 center 对称位置的 mirrori 为中心的回文串覆盖范围没有到达 center 为中心的回文串边缘,则 i 为中心的回文串肯定和 mirrori 的一样。而如果 mirrori 的回文串到达了边缘甚至超过,或者 i 本来就在 reach 的右边,那么对 i 为中心的回文串进行一次扩展,则结果 或者刚好不扩展,或者一定更新了reach。无论怎样,这里都得到了 r[i]。知道了所有 r[i],答案就出来了。

    核心问题在于第4步“对 i 为中心的回文串进行扩展”的复杂度。每次发生“对 i 扩展“,必然是对 reach 的扩展(也可能刚好不扩展,这个不影响复杂度),而 reach 的扩展范围是 tmp 的长度大约 2n,所以总复杂度为 O(n)。

     1 class Solution {
     2 public:
     3     string longestPalindrome(string s) {
     4         int center = 1, reach = 1, ansstart = 0, anslength = 0;
     5         string tmp = "!#";
     6         for(int i = 0; i < s.length(); i ++)
     7             tmp += s[i], tmp += '#';
     8         tmp + '!';
     9         vector<int> r(tmp.length());
    10         for(int i = 2; i < tmp.length(); i ++)
    11         {
    12             int mirrori = center * 2 - i;
    13             r[i] = reach > i ? min(r[mirrori], reach - i) : 0;
    14             for(; tmp[i + r[i] + 1] == tmp[i - r[i] - 1]; r[i] ++);
    15             if(i + r[i] > reach) reach = i + r[i], center = i;
    16             if(r[i] > anslength)
    17             {
    18                 ansstart = i - r[i] >> 1;
    19                 anslength = r[i];
    20             }
    21         }
    22         return s.substr(ansstart, anslength);
    23     }
    24 };
    View Code

    Add Two Numbers

    大整数加法的链表版。

     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 *addTwoNumbers(ListNode *l1, ListNode *l2) {
    12         ListNode *ans = new ListNode(0), *p = ans;
    13         int cur = 0;
    14         while(l1 != NULL || l2 != NULL || cur)
    15         {
    16             p->val = (l1 ? l1->val : 0) + (l2 ? l2->val : 0) + cur;
    17             cur = p->val / 10;
    18             p->val %= 10;
    19             if(l1) l1 = l1->next;
    20             if(l2) l2 = l2->next;
    21             if(l1 || l2 || cur)
    22                 p->next = new ListNode(0);
    23             p = p->next;
    24         }
    25         return ans;
    26     }
    27 };
    View Code

    Longest Substring Without Repeating Characters

    维护一个不重复字符的区间。

    代码一:

     1 class Solution {
     2 public:
     3     int lengthOfLongestSubstring(string s) {
     4         vector<bool> isin(128, false);
     5         int ans = 0;
     6         for(int front = 0, rear = 0; front < s.length(); front ++)
     7         {
     8             if(isin[s[front]])
     9                 for(; rear < front && isin[s[front]]; isin[s[rear]] = false, rear ++);
    10             isin[s[front]] = true;
    11             ans = max(ans, front - rear + 1);
    12         }
    13         return ans;
    14     }
    15 };
    View Code

    代码二:

     1 class Solution {
     2 public:
     3     int lengthOfLongestSubstring(string s) {
     4         vector<int> site(128, -1);
     5         int nowstart = -1, ans = 0;
     6         for(int i = 0; i < s.length(); i ++)
     7         {
     8             if(site[s[i]] >= nowstart)
     9                 nowstart = site[s[i]] + 1;
    10             site[s[i]] = i;
    11             ans = max(i - nowstart + 1, ans);
    12         }
    13         return ans;
    14     }
    15 };
    View Code

    Median of Two Sorted Arrays

     如果 A[pa] < B[pb],那么 A[pa] 一定在 A 与 B 合并后的前 pa + pb + 2 个数中。

    证明: A 中有 pa + 1 个数 <= A[pa],B 中有小于 pb + 1 个数 <= A[pa],合并后有少于pa + pb + 2 个数 <= A[pa]。

    利用这个性质迭代找 A 与 B 合并后的第 k 大数。

     1 class Solution {
     2 public:
     3     int findKth(int A[], int m, int B[], int n, int k)
     4     {
     5         int pm, pn;
     6         while(true)
     7         {
     8             if(m == 0) return B[k - 1];
     9             if(n == 0) return A[k - 1];
    10             if(k == 1) return min(A[k - 1], B[k - 1]);
    11             if(m <= n) pm = min(k >> 1, m), pn = k - pm;
    12             else pn = min(k >> 1, n), pm = k - pn;
    13             if(A[pm - 1] < B[pn - 1]) A += pm, m -= pm, k -= pm;
    14             else if(A[pm - 1] > B[pn - 1]) B += pn, n -= pn, k-= pn;
    15             else break;
    16         }
    17         return A[pm - 1];
    18     }
    19     double findMedianSortedArrays(int A[], int m, int B[], int n) {
    20         if((m + n) & 1) return findKth(A, m, B, n, (m + n >> 1) + 1);
    21         else return (findKth(A, m, B, n, m + n >> 1) + 
    22             findKth(A, m, B, n, (m + n >> 1) + 1)) * 0.5;
    23     }
    24 };
    View Code

    Two Sum

    哈希存位置,O(n)。

     1 class Solution {
     2 public:
     3     vector<int> twoSum(vector<int> &numbers, int target) {
     4         unordered_map<int, int> mp;
     5         vector<int> ans;
     6         for(int i = 0; i < numbers.size(); i ++)
     7         {
     8             if(mp.count(target - numbers[i]))
     9             {
    10                 ans.push_back(mp[target - numbers[i]] + 1);
    11                 ans.push_back(i + 1);
    12                 break;
    13             }
    14             if(!mp.count(numbers[i])) mp[numbers[i]] = i;
    15         }
    16         return ans;
    17     }
    18 };
    View Code
  • 相关阅读:
    PyCharm配置SFTP远程调试Django应用
    linux安装mysql详细步骤
    一些unity问题的收集
    主程之路
    【英宝通Unity4.0公开课学习 】(六)76讲到90讲
    【英宝通Unity4.0公开课学习 】(五)47讲到75讲
    【英宝通Unity4.0公开课学习 】(四)GUI到物理引擎
    【英宝通Unity4.0公开课学习 】(三)脚本使用
    【英宝通Unity4.0公开课学习 】(二)场景创建
    【英宝通Unity4.0公开课学习 】(一)资源管理
  • 原文地址:https://www.cnblogs.com/CSGrandeur/p/3520937.html
Copyright © 2011-2022 走看看