LeetCode

作者: 蕾娜漢默 | 来源:发表于2017-03-21 20:11 被阅读1897次

    LeetCode 刷题随手记 - 第一部分

    前 256 题(非会员),仅算法题,的吐槽

    https://leetcode.com/problemset/algorithms/

    说明

    刷题指南

    • 不要背题,前面的基本题型需要熟悉
    • 不要刷太多题
    • 前面的基本题型需要熟悉
    • 记模版

    背题很容易忘,而且题目有具体的要求,还总会有新的题目。
    模板,比如大数、回溯、图的深度优先搜索、动态规划。
    一次刷一定量的题,方便类比和补遗。对照课本上的知识点。
    总之,为了解决题目,不是单独扯道理。

    关于 LeetCode

    • 是针对白板编程设计的题目

    • 手写,

    • 测试

    • AC

    • LeetCode 的题目还都是基础题,白板编程的,自己写测试

    • AC 仍可能不对

    • 不 AC 不一定错,比如 LeetCode 改题目了

    • AC

      • 对特殊值处理可能不对
      • 与题目中对实现方式的要求不一致
    • Leetcode 没有对异常输入的处理

    • 有些课本上的知识点目前的有没有涵盖到的

    • 而且仅算法题的涵盖也有点窄

    • 不要在题目的范围和已有的题目上限制

      • 其他方面的基础知识,未知的题目的分析方法

    每道题选择一个标签,为了按方法分类

    • 题后的标签用来按解法归类
      • 只指定一个类别,

    比如 Array+DP 的

    按题号排列,从学习的角度,归类更好。

    解答

    使用 C/C++,按题号顺序。

    分类学习。

    1. Two Sum

    • 哈希表,O(N)
    • 或者先排序再查找,如果不是返回下标

    要点

    1. 数组遍历:用 for 循环,可以求和,最大值,最大值的下标,元素是否存在。
    2. 双指针:同向,可以两头,可以嵌套。可以快慢,先后,收缩。
    class Solution {
    public:
        vector<int> twoSum(vector<int>& nums, int target) {
            unordered_map<int,int> h;
            for(int i=0;;i++){
                int x = nums[i];
                if(h.count(x))
                    return {h[x],i};
                h[target-x] = i;
            }
        }
    };
    

    2. Add Two Numbers

    • 链表,遍历和尾插
    • 大数,加法

    要点

    1. 大数:用一个整数表示大数中一位(或几位),计算加法时产生进位。
    2. 链表:和数组都是基础的容器。链表是递归的结构,可以递归遍历,尾递归写成循环。可以直接头部插入或尾部插入(记录最后节点)。为处理空链表方便,可以通过额外的头节点。
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
            ListNode* list = NULL;
            ListNode** p = &list;
            int s = 0;
            while(l1 || l2 || s){
                if(l1){
                    s+ = l1->val;
                    l1 = l1->next;
                }
                if(l2){
                    s+ = l2->val;
                    l2 = l2->next;
                }
                *p = new ListNode(s%10);
                p = &(*p)->next;
                s /= 10;
            }
            return list;
        }
    };
    

    3. Longest Substring Without Repeating Characters

    • 数组
    • 动态规划
    • O(N)

    要点

    1. 双指针:一个向前一步,另一个根据条件收缩。该题在遍历时记录最大值。
    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            int y = 0;
            int b[128] = {0};
            int l = 0;
            for(int i=0;i<s.size();i++){
                char c = s[i];
                l = max(l,b[c]);
                y = max(y,i-l+1);
                b[c] = i+1;
            }
            return y;
        }
    };
    
    class Solution {
    public:
        int lengthOfLongestSubstring(string s) {
            int y = 0;
            vector<int> b(128, -1);
            int a = -1;
            for(int i=0;i<s.size();i++){
                char c = s[i];
                a = max(a,b[c]);
                y = max(y,i-a);
                b[c] = i;
            }
            return y;
        }
    };
    

    4. Median of Two Sorted Arrays

    要点

    1. 双有序数组:搜索时,可以归并为一个数组执行查找,也可以直接在双数组上查找。
    class Solution {
        double find(vector<int>& A, vector<int>& B, int k){
            int a = 0, b = 0;
            for(;;){
                if(k==0){
                    if(!(b<B.size()) || (a<A.size() && A[a]<B[b]))
                        return A[a];
                    else
                        return B[b];
                }
                int c = (k-1)/2;
                if(!(b+c<B.size()) || (a+c<A.size() && A[a+c]<=B[b+c])){
                    a += c+1;
                    k -= c+1;
                }else{
                    b += c+1;
                    k -= c+1;
                }
                
            }
        }
    public:
        double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
            int length = nums1.size() + nums2.size();
            if(length%2)
                return find(nums1,nums2,length/2);
            else
                return (find(nums1,nums2,length/2-1)+find(nums1,nums2,length/2))/2.0;
        }
    };
    
    double find(int* nums1, int nums1Size, int* nums2, int nums2Size, int k){
        for(;;){
            if(nums1Size>nums2Size){
                int* nums3 = nums2;
                nums2 = nums1;
                nums1 = nums3;
                nums1Size = nums1Size^nums2Size;
                nums2Size = nums1Size^nums2Size;
                nums1Size = nums1Size^nums2Size;
            }else if(nums1Size==0){
                return nums2[k-1];
            }else if(k==1){
                return nums1[0]<nums2[0] ? nums1[0] : nums2[0];
            }else{
                int k1 = k/2 < nums1Size ? k/2 : nums1Size;
                int k2 = k - k1;
                if(nums1[k1-1]==nums2[k2-1]){
                    return nums1[k1-1];
                }else if(nums1[k1-1]<nums2[k2-1]){
                    nums1 += k1;
                    nums1Size -= k1;
                    k -= k1;
                }else{
                    nums2 += k2;
                    nums2Size -= k2;
                    k -= k2;
                }
            }
        }
    }
    double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
        int length = nums1Size + nums2Size;
        double med = find(nums1, nums1Size, nums2, nums2Size, length/2+1);
        if(length%2==0)
            med = (med+find(nums1, nums1Size, nums2, nums2Size, length/2))/2;
        return med;
    }
    

    5. Longest Palindromic Substring

    • 动态规划,后面回文子串的题目还会用到
      • 从前往后,计算前缀,或者从后往前,计算后缀都可以
    • 这题也有别的更好的方法。
    class Solution {
    public:
        string longestPalindrome(string s) {
            int len = 0, start;
            int n = s.size();
            auto f = [&](int j, int k){
                while(j>=0 && k<n && s[j]==s[k]){
                    j--, k++;
                }
                if(k-j-1>len){
                    len = k-j-1;
                    start = j+1;
                }
            };
            for(int i=0; i<n; i++){
                f(i, i);
                f(i, i+1);
            }
            return s.substr(start, len);
        }
    };
    
    class Solution {
    public:
        string longestPalindrome(string s) {
            int len = 0, start;
            int n = s.size();
            bool d[n][n];
            memset(d, 0, sizeof(bool)*(n*n));
            for(int i=0; i<n; i++){
                for(int j=0;j<=i; j++){
                    d[j][i] = s[j]==s[i] && (i-j<3 ||d[j+1][i-1]);
                    if(d[j][i] && (i-j+1) > len){
                        len = i - j + 1;
                        start = j;
                    }
                    
                }
            }
            return s.substr(start, len);
        }
    };
    

    6. ZigZag Conversion

    • 存在下标周期性映射关系
    • 分析 r=1,2,3,4,5 的情况
    class Solution {
    public:
        string convert(string s, int numRows) {
            if(numRows==1)
                return s;
            int d = 2*numRows-2;
            string y;
            for(int i=0; i<numRows; i++){
                for(int j=i; j<s.size(); j+=d){
                    y.push_back(s[j]);
                    if(i!=0 && i!=numRows-1){
                        int k = j+d-i*2;
                        if(k < s.size()){
                            y.push_back(s[k]);
                        }
                    }
                }
            }
            return y;
        }
    };
    
    // numRows = 5
    // 0     8         16
    // 1   7 9      15 17
    // 2  6  10   14
    // 3 5   11 13
    // 4     12
    
    // 0   4
    // 1 3 5 7
    // 2   6
    
    // 0 2
    // 1 3
    
    // 0 1 2 3
    

    7. Reverse Integer

    Integer

    • 32位补码表示有符号整数
    • 符号不变,转换结果可能会溢出

    要点

    1. 十进制:用取模和整数除法,可以得到最低位和余下的高位。
    2. 整型溢出:运算后超出表示范围,可以在运算前,或者运算后检查
    class Solution {
    public:
        int reverse(int x) {
            int a = x>0 ? INT_MAX : INT_MIN;
            int b = a/10, c = a%10;
            int y = 0;
            for(;x>=10 || x<=-10; x /= 10)
                y = y*10 + x%10;
            if(x>0)
                return y<b || (y==b && x<=c) ? y*10+x : 0;
            else
                return y>b || (y==b && x>=c) ? y*10+x : 0;
        }
    };
    
    class Solution {
    public:
        int reverse(int x) {
            int a = x>=0 ? INT_MAX : INT_MIN;
            int b = a/10, c = a%10;
            int y = 0;
            if(x>=0){
                for(;x>=10; x /= 10)
                    y = y*10 + x%10;
                return y<b || (y==b && x<=c) ? y*10+x : 0;
            }else{
                for(;x<=-10; x /= 10)
                    y = y*10 + x%10;
                return y>b || (y==b && x>=c) ? y*10+x : 0;
            }
        }
    };
    

    这道题 LeetCode 的 Blog 上的解法挺不错的

    8. String to Integer (atoi)

    • 字符串转整数,实现 C 语言的字符串类库函数
    • 可以用 7. Reverse Integer 用到的溢出的判断方法
      • 区分处理正负补码的表示范围
    int myAtoi(char* str) {
        while(isspace(*str))
            str++;
        int neg = 0;
        switch(*str){
            case '-':
                neg = 1;
            case '+':
                str++;
                break;
        }
        if(!isdigit(*str))
            return 0;
        int a, b;
        if(!neg)
            a = INT_MAX/10, b = INT_MAX%10;
        else
            a = -(INT_MIN/10), b = -(INT_MIN%10);
        int value = 0;
        while(isdigit(*str)){
            int digit = *str-'0';
            if(value>a || (value==a && digit>b))
                return neg ? INT_MIN : INT_MAX;
            value = value*10 + digit;
            str++;
        }
        return neg ? -value : value;
    }
    

    9. Palindrome Number

    • 逐对比较
    • 十进制自然数运算
      取最高位和最低位
    class Solution {
    public:
        bool isPalindrome(int x) {
            if(x<0)
                return false;
            int c = 1;
            while(x/c>=10)
                c *= 10;
            while(x){
                if((x/c)!=(x%10))
                    return false;
                x = (x%c)/10;
                c /= 100;
            }
            return true;
        }
    };
    

    10. Regular Expression Matching

    • 递归/回溯处理字符串后缀
    • 注意各种情况的组合
    class Solution {
        bool _isMatch(const char* s, const char* p) {
            if(*p==0){
                return *s==0;
            }else if(*(p+1)=='*'){
                if(*s==0)
                    return _isMatch(s, p+2);
                else if(*s==*p || *p=='.')
                    return _isMatch(s+1, p) || _isMatch(s, p+2);
                else
                    return _isMatch(s, p+2);
            }else{
                if(*s==0)
                    return false;
                if(*s==*p || *p=='.')
                    return _isMatch(s+1, p+1);
                else
                    return false;
            }
        }    
    public:
        bool isMatch(string s, string p) {
            return _isMatch(s.c_str(), p.c_str());
        }
    };
    

    11. Container With Most Water

    • 数组,动态规划,双指针
    • 能装最多的水
    • 双指针,从两头,次高往最高收缩
    class Solution {
    public:
        int maxArea(vector<int>& height) {
            int i = 0, j = height.size()-1;
            int m = 0;
            while(i<j){
                m = max(m, min(height[i],height[j])*(j-i));
                if(height[i] < height[j])
                    i++;
                else
                    j--;
            }
            return m;
        }
    };
    

    12. Integer to Roman

    • 罗马数字转换,输入为 1 到 3999
    class Solution {
    public:
        string intToRoman(int num) {
            int integers[13] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
            char* romans[13] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
            string sb;
            for(int i=0; i<13; i++){
                for(int j=num/integers[i]; j--;)
                    sb += romans[i];
                num %= integers[i];
            }
            return sb;
        }
    };
    

    13. Roman to Integer

    • 罗马数字转换
    int romanToInt(char* s) {
        int integers[13] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        char* romans[13] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
        int result = 0;
        for(int i=0; i<13; i++){
            while(!memcmp(s, romans[i], strlen(romans[i]))){
                result += integers[i];
                s += strlen(romans[i]);            
            }
        }
        return result;
    }
    

    14. Longest Common Prefix

    • 字符串比较,公共前缀
      直接按题意实现即可
    char* longestCommonPrefix(char** strs, int strsSize) {
        char *result;
        if(strsSize==0){
            result = (char*)malloc(sizeof(char));
            result[0] = 0;
            return result;
        }
        int count = 0;
        for(;;){
            char ch = strs[0][count];
            if(ch==0)
                break;
            for(int j=1; j<strsSize; j++)
                if(strs[j][count]!=ch)
                    goto end_for;
            count++;
        }
        end_for:
        result = (char*)malloc(sizeof(char)*(count+1));
        memcpy(result,strs[0],sizeof(char)*count);
        result[count] = 0;
        return result;
    }
    

    15. 3Sum

    • 排序然后查找
      • 这题有重复元素,比如 [-1, -1, 2] ,如果最后再去重可能会超时
    • 注意 .size() 返回的是 unsigned,若判断 <.size()-1 会一直循环
      或者用哈希表
    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> result;
            sort(nums.begin(), nums.end());
            int n = nums.size();
            for(int i=0; i<n-2; i++){
                if(i!=0 && nums[i]==nums[i-1])
                    continue;
                int j = i+1, k = nums.size()-1;
                while(j < k){
                    int s = nums[i] + nums[j] + nums[k];
                    if(s==0){
                        result.push_back({nums[i], nums[j], nums[k]});
                        j++, k--;
                    }else if(s<0){
                        j++;
                    }else{
                        k--;
                    }
                    while(j!=i+1 && nums[j]==nums[j-1])
                        j++;
                    while(k!=nums.size()-1 && nums[k]==nums[k+1])
                        k--;                    
                }
            }
            return result;
        }
    };
    
    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector<vector<int>> result;
            sort(nums.begin(), nums.end());
            int n = nums.size();
            for(int i=0; i<n-2 && nums[i]<=0; i++){
                if(i!=0 && nums[i]==nums[i-1])
                    continue;
                int j = i+1, k = nums.size()-1;
                while(j < k){
                    int s = nums[i] + nums[j] + nums[k];
                    if(s==0){
                        result.push_back({nums[i], nums[j], nums[k]});
                        j++, k--;
                    }else if(s<0){
                        j++;
                    }else{
                        k--;
                    }
                    while(j!=i+1 && nums[j]==nums[j-1])
                        j++;
                    while(k!=nums.size()-1 && nums[k]==nums[k+1])
                        k--;                    
                }
            }
            return result;
        }
    };
    

    16. 3Sum Closest

    Search

    • 先排序
    • 或者用哈希
    class Solution {
    public:
        int threeSumClosest(vector<int>& nums, int target) {
            int ans = 0, d = INT_MAX;
            sort(nums.begin(), nums.end());
            if(nums.size()<3)
                return 0;
            for(int i=0; i<nums.size()-2; i++){
                if(i!=0 && nums[i]==nums[i-1])
                    continue;
                int j = i+1, k = nums.size()-1;
                while(j < k){
                    int s = nums[i] + nums[j] + nums[k] - target;
                    if(abs(s)<d){
                        d = abs(s);
                        ans = s + target;
                    }
                    if(s==0){
                        j++, k--;
                    }else if(s<0){
                        j++;
                    }else{
                        k--;
                    }
                    while(j!=i+1 && nums[j]==nums[j-1])
                        j++;
                    while(k!=nums.size()-1 && nums[k]==nums[k+1])
                        k--;
                }
            }
            return ans;        
        }
    };
    

    17. Letter Combinations of a Phone Number

    • 递归,回溯,排列组合

    要点
    回溯:

    class Solution {
    public:
        vector<string> letterCombinations(string digits) {
            vector<string> result;
            if(digits.size()==0)
                return result;
            string y = digits;
            int n = digits.size();
            char b[digits.size()+1];
            b[n] = 0;
            char* s[10] = {
              "","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"  
            };
            function<void(int)> f = [&](int i){
                if(i==digits.size()){
                    result.push_back(b);
                }else{
                    for(char *p = s[digits[i]-'0']; *p; p++){
                        b[i] = *p;
                        f(i+1);
                    }
                }
            };
            f(0);
            return result;
        }
    };
    

    18. 4Sum

    class Solution {
    public:
        vector<vector<int>> fourSum(vector<int>& nums, int target) {
            vector<vector<int>> ans;
            sort(nums.begin(), nums.end());
            for(int x:nums)printf("%d ",x);puts("");
            int n = nums.size();
            for(int i=0; i<n-3; i++){
                if(i!=0 && nums[i]==nums[i-1])
                    continue;
                for(int j=i+1; j<n-2; j++){
                    if(j!=i+1 && nums[j]==nums[j-1])
                        continue;
                    int k = j + 1, l = n-1;
                    while(k<l){
                        int sum = nums[i]+nums[j]+nums[k]+nums[l];
                        if(sum==target){
                            ans.push_back({nums[i],nums[j],nums[k],nums[l]});
                            k++, l--;
                        }else if(sum<target){
                            k++;
                        }else{
                            l--;
                        }
                        while(k!=j+1 && k<l && nums[k]==nums[k-1])
                            k++;
                        while(l!=n-1 && k<l && nums[l]==nums[l+1])
                            l--;
                    }
                }
            }
            return ans;
        }
    };
    

    19. Remove Nth Node From End of List

    • 链表,双指针
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
        struct ListNode* p = head;
        while(n--)
            p = p->next;
        if(p==NULL)
            return head->next;
        p = p->next;
        struct ListNode* q = head;
        while(p){
            q = q->next;
            p = p->next;
        }
        q->next = q->next->next;
        return head;
    }
    

    20. Valid Parentheses

    • 栈,先进后出
      要点
      stack
    bool isValid(char* s) {
        const char *ps = "([{)]}";
        int stack_size = 3;
        char *stack = (char*)malloc(sizeof(char)*stack_size);
        char *push = stack;
        for(char x; x=*s++;){
            char* found = strchr(ps, x);
            if(found){
                int a = found - ps;
                if(a<3){
                    if(push==stack+stack_size){
                        stack = (char*)realloc(stack,sizeof(char)*(stack_size<<1));
                        push = stack + stack_size;
                        stack_size <<= 1;
                    }
                    *push++ = ps[a+3];
                }else{
                    if(push<=stack || push[-1]!=x)
                        return false;
                    push--;
                }
            }
        }
        return push==stack;
    }
    

    21. Merge Two Sorted Lists

    • 链表的节点操作
    • 有序序列的归并
      要点:节点题通常会要求不改变元素,但也不一定。
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
            ListNode* head = NULL;
            ListNode** append = &head; 
            for(;;){
                if(!l1){
                    *append = l2;
                    break;
                }
                if(!l2){
                    *append = l1;
                    break;
                }
                if(l1->val<l2->val){
                    *append = l1;
                    l1 = l1->next;
                }else{
                    *append = l2;
                    l2 = l2->next;
                }
                append = &(*append)->next;
            }
            return head;
        }
    };
    

    22. Generate Parentheses

    • 递归,回溯
    class Solution {
    public:
        vector<string> generateParenthesis(int n) {
            vector<string> result;
            string item(n*2, ' ');
            function<void(int,int)> f = [&](int i,int s){
                if(i==n*2){
                    result.push_back(item);
                    return;
                }
                if(s > 0){
                    item[i] = ')';
                    f(i+1, s-1);
                }
                if(s < 2*n - i){
                    item[i] = '(';
                    f(i+1, s+1);
                }
            };
            f(0, 0);
            return result;
        }
    };
    

    23. Merge k Sorted Lists

    • 归并排序,链表
    • 两两归并,次数
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
        struct ListNode* head = NULL;
        struct ListNode** append = &head; 
        for(;;){
            if(!l1){
                *append = l2;
                break;
            }
            if(!l2){
                *append = l1;
                break;
            }
            if(l1->val<l2->val){
                *append = l1;
                l1 = l1->next;
            }else{
                *append = l2;
                l2 = l2->next;
            }
            append = &(*append)->next;
        }
        return head;
    } 
    struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
        if(listsSize==0)
            return NULL;
        if(listsSize==1)
            return lists[0];
        if(listsSize==2)
            return mergeTwoLists(lists[0], lists[1]);
        return mergeTwoLists(mergeKLists(lists,listsSize/2),mergeKLists(lists+listsSize/2,listsSize-listsSize/2));
    }
    

    24. Swap Nodes in Pairs

    • 链表
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* swapPairs(ListNode* head) {
            auto list = new ListNode(-1);
            list->next = head;
            auto p = list;
            while(p->next){
                auto a = p->next;
                auto b = a->next;
                if(!b)
                    break;
                auto c = b->next;
                a->next = c;
                b->next = a;
                p->next = b;
                p = a;
            }
            return list->next;
        }
    };
    

    25. Reverse Nodes in k-Group

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* reverseKGroup(ListNode* head, int k) {
            auto list = new ListNode(-1);
            list->next = head;
            auto last = list;
            for(;;){
                auto list2 = last;
                int n = k;
                while(n && last->next){
                    n--;
                    last = last->next;
                }
                if(n)
                    break;
                ListNode* prev = last->next;
                ListNode* node = list2->next;
                for(int i=0; i<k; i++){
                    auto next = node->next;
                    node->next = prev;
                    prev = node;
                    node = next;
                }
                last = list2->next;
                list2->next = prev;
                
            }
            return list->next;
        }
    };
    
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    struct ListNode* reverseKGroup(struct ListNode* head, int k) {
        struct ListNode **append = &head;
        for(;;){
            struct ListNode **list = append;
            int n = k;
            while(n && *append){
                append = &(*append)->next;
                n--;
            }
            if(n)
                break;
            struct ListNode *prev = *append;
            struct ListNode *node = *list;
            for(int i=0; i<k; i++){
                struct ListNode *next = node->next;
                node->next = prev;
                prev = node;
                node = next;
            }
            auto append2 = &(*list)->next;        
            *list = prev;
            append = append2;
        }
        return head;
    }
    

    26. Remove Duplicates from Sorted Array

    • 去重,通过排序。
    int removeDuplicates(int* nums, int numsSize) {
        if(numsSize==0)
            return 0;
        int *s = nums;
        for(int i=1; i<numsSize;i++){
            if(nums[i]!=*s){
                *++s = nums[i];
            }
        }
        return s - nums + 1;
    }
    

    27. Remove Element

    • 数组
    • 双指针
    int removeElement(int* nums, int numsSize, int val) {
        int *s = nums;
        for(int i=0; i<numsSize; i++){
            if(nums[i]!=val)
                *s++ = nums[i];
        }
        return s - nums;
    }
    

    28. Implement strStr()

    Search

    • 库函数 strstr 实现为 O(MN) ,平时需要 O(N) 就用正则表达式生成状态机

    要点

    1. 前缀:字符串头部的连续字符构成的子串。该子串可能会在字符串内重复出现。
    class Solution {
        int* built_table(string& m){
            int *T = new int[m.size()];
            T[0] = -1;
            T[1] = 0;
            for(int i=2, j=0; i<m.size(); ){
                printf("> %d \n",i);
                if(m[i-1] == m[j]){
                    T[i] = j + 1;
                    i++, j++;
                }else if(j>0){
                    j = T[j];
                }else{
                    T[i] = 0;
                    i++;
                }
            }
            return T;
        }
        int search(string &s, string &m){
            if(m.size()==0)
                return 0;
            auto next = built_table(m);
            for(int i=0, j=0; i<s.size();){
                if(m[j]==s[i]){
                    if(j+1==m.size()){
                        return i-j;
                    }else{
                        i++, j++;
                    }
                }else{
                    if(next[j]!=-1){
                        j = next[j];
                    }else{
                        i++;
                        j = 0;
                    }
                }
            }
            return -1;
        }
    public:
        int strStr(string haystack, string needle) {
            return search(haystack, needle);
        }
    };
    

    稍微改一下,上面的删掉,也有其他写法

    class Solution {
        int* built_table(string& m){
            int *T = new int[m.size()];
            T[0] = -1;
            T[1] = 0;
            for(int i=2, j=0; i<m.size(); ){
                if(m[i-1] == m[j]){
                    T[i] = j + 1;
                    i++, j++;
                }else if(j!=0){
                    j = T[j];
                }else{
                    T[i] = 0;
                    i++;
                }
            }
            return T;
        }
        int search(string &s, string &m){
            if(m.size()==0)
                return 0;
            auto next = built_table(m);
            for(int i=0, j=0; i<s.size();){
                if(m[j]==s[i]){
                    if(j+1==m.size())
                        return i-j;
                    else
                        i++, j++;
                }else{
                    if(j!=0)
                        j = next[j];
                    else
                        i++;
                }
            }
            return -1;
        }
    public:
        int strStr(string haystack, string needle) {
            return search(haystack, needle);
        }
    };
    

    这样也行

    int strStr(char* s1, char* s2) {
        int m = strlen(s2);
        if(m==0)
            return 0;
        int n = strlen(s1);
        int b[m+1];
        int i, j;
        i = 0, j = -1;
        b[i] = j;
        while(i<m){
            while(j>=0 && s2[i]!=s2[j])
                j = b[j];
            i++, j++;
            if(s2[i]==s2[j])
                b[i] = b[j];
            else
                b[i] = j;
        }
        i = j = 0;
        while(i<n){
            while(j>=0 && s1[i]!=s2[j])
                j = b[j];
            i++, j++;
            if(j==m)
                return i-j;
        }
        return -1;
    }
    
    int strStr(char* s1, char* s2) {
        int m = strlen(s2);
        if(m==0)
            return 0;
        int n = strlen(s1);
        int b[m+1];
        int i, j;
        i = 0, j = -1;
        b[i] = j;
        while(i<m){
            while(j>=0 && s2[i]!=s2[j])
                j = b[j];
            i++, j++;
            b[i] = j;
        }
        i = j = 0;
        while(i<n){
            while(j>=0 && s1[i]!=s2[j])
                j = b[j];
            i++, j++;
            if(j==m)
                return i-j;
        }
        return -1;
    }
    

    29. Divide Two Integers

    • 整数运算,通过除法和取模
    int divide(int dividend, int divisor) {
        if(divisor==0)
            return INT_MAX;
        unsigned a = dividend>=0 ? dividend : -dividend;
        unsigned b = divisor>=0 ? divisor : -divisor;
        unsigned c = 0;
        int n = 0;
        for(unsigned i=b; i<a; i<<=1)
            n++;
        for(int i=n; i>=0; i--){
            if((b<<i)<=a){ 
                c += (1<<i);
                a -= (b<<i);
            }
        }
        if((dividend>0 && divisor<0) || (dividend<0 && divisor>0))
            return -c;
        return c>INT_MAX ? INT_MAX : c;
    }
    

    30. Substring with Concatenation of All Words

    Array

    class Solution {
    public:
        vector<int> findSubstring(string s, vector<string>& words) {
            vector<int> ans;
            unordered_map<string,int> count;
            for(auto& x: words)
                count[x]++;
            int n = words.at(0).size();
            int m = n*words.size();
            for(int i=0,e = s.size()-m+1; i<e; i++){
                unordered_map<string,int> copy(count);
                for(int j=0; j<words.size(); j++){
                    auto x = s.substr(i+j*n, n);
                    auto it = copy.find(x);
                    if(it!=copy.end() && it->second)
                        copy[x]--;
                    else
                        goto out;
                }
                ans.push_back(i);
                out:;
            }
            return ans;
        }
    };
    

    31. Next Permutation

    • 排列组合,求下一个排列
    • 函数不保存额外的状态,每次调用独立
    • 三个元素则依次为 123,132,213,231,312,321
      • 值的大小按升序排列,123 开始 321 结束
      • 每一位的值表示序号,唯一且有限个
    • 从右往左找到第一个小于右侧元素的 A
      • 这是可以增大的最低位(从右往左)
        • A 右侧一定是降序序列
      • 没找到(如 321)则逆置整个排列
      • 找到则找到比 A 大的最低位 B
        • B 一定是 A 右侧比 A 大的最小值
      • A, B 互换,低于 A 的位逆置(从降序变成升序)

    要点

    1. 升序:等长序列之间也可构成偏序关系。
    class Solution {
    public:
        void nextPermutation(vector<int>& nums) {
            int n = nums.size();
            int l = n-1;
            while(l>0 && !(nums[l-1]<nums[l]))
                l--;
            if(l>0){
                int r = n-1;
                while(!(nums[l-1]<nums[r]))
                    r--;
                swap(nums[l-1], nums[r]);
            }
            for(int r=n-1;l<r;l++,r--)
                swap(nums[l], nums[r]);
                
        }
    };
    

    32. Longest Valid Parentheses

    • 可以用动态规划来做
    class Solution {
    public:
        int longestValidParentheses(string s) {
            int len = 0, start = -1;
            stack<int> st;
            for(int i=0; i<s.size(); i++){
                if(s[i]=='('){
                    st.push(i);
                }else if(!st.empty()){
                    st.pop();
                    if(!st.empty()){
                        len = max(len, i-st.top());
                    }else{
                        len = max(len, i-start);
                    }
                }else{
                    start = i;
                }
            }
            return len;
        }
    };
    

    33. Search in Rotated Sorted Array

    Search

    • 二分查找
    int search(int* A, int n, int target) {
        int a = 0, b = n;
        while(a<b){
            int c = a+(b-a)/2;
            if(A[c]==target){
                return c;
            }else if(A[a]<=A[c]){
                if(A[a]<=target && target<A[c])
                    b = c;
                else
                    a = c + 1;
            }else{
                if(A[c]<target && target<=A[b-1])
                    a = c + 1;
                else
                    b = c;
            }
        }
        return -1;
    }
    

    34. Search for a Range

    Search

    • 二分查找
    class Solution {
        int lower(vector<int>& nums, int target){
            int a = 0, b = nums.size();
            while(a<b){
                int c = (a+b)/2;
                if(nums[c]<target){
                    a = c + 1;
                }else{
                    b = c;
                }
            }
            return b;   
        }
        int upper(vector<int>& nums, int target){
            int a = 0, b = nums.size();
            while(a<b){
                int c = (a+b)/2;
                if(nums[c]<=target){
                    a = c + 1;
                }else{
                    b = c;
                }
            }
            return a-1;
        }
    public:
        vector<int> searchRange(vector<int>& nums, int target) {
            int low = lower(nums,target);
            int high = upper(nums,target);
            if(low<=high)
                return {lower(nums,target), upper(nums,target)};
            else
                return {-1, -1};
        }
    };
    

    35. Search Insert Position

    • 注意右边界是否包含
      • 以及终止条件,和连续相等元素的处理
    int searchInsert(int* nums, int numsSize, int target) {
        int a = 0, b = numsSize;
        while(a<b){
            int c = (a+b)/2;
            if(nums[c]==target){
                return c;
            }else if(nums[c]<target){
                a = c + 1;
            }else{
                b = c;
            }
        }
        return a;
    }
    

    36. Valid Sudoku

    • 判断数独局面是否正确
      三个条件
    class Solution {
    public:
        bool isValidSudoku(vector<vector<char>>& board) {
            bool flag[9];
            memset(flag, 0, sizeof(bool)*9);
            for(int i=0; i<9; i++){
                for(int j=0; j<9; j++){
                    if(board[i][j]=='.')
                        continue;
                    if(flag[board[i][j]-'1'])
                        return false;
                    flag[board[i][j]-'1'] = true;
                }
                memset(flag, 0, sizeof(bool)*9);
                for(int j=0; j<9; j++){
                    if(board[j][i]=='.')
                        continue;
                    if(flag[board[j][i]-'1'])
                        return false;
                    flag[board[j][i]-'1'] = true;
                }
                memset(flag, 0, sizeof(bool)*9);
                for(int j=0; j<9; j++){
                    int x=(i%3)*3+j%3;
                    int y=(i/3)*3+j/3;
                    if(board[x][y]=='.')
                        continue;
                    if(flag[board[x][y]-'1'])
                        return false;
                    flag[board[x][y]-'1'] = true;                
                }
                memset(flag, 0, sizeof(bool)*9);
            }
            return true;
        }
    };
    

    37. Sudoku Solver

    • 回溯
    • 有其他高效的算法
    class Solution {
    public:
        void solveSudoku(vector<vector<char>>& board) {
            unsigned t[3][9] = {0};
            for(int y=0; y<9; y++)
                for(int x=0; x<9; x++){
                    int z = x/3 + y/3*3;
                    if(board[y][x]!='.'){
                        int b = board[y][x]-'1';
                        t[0][x] |= (1<<b);
                        t[1][y] |= (1<<b);
                        t[2][z] |= (1<<b);
                    }
                     
                }
            function<bool(int)> f = [&](int k){
                if(k==81){
                    return true;
                }
                int x = k%9, y = k/9;
                if(board[y][x]!='.')
                    return f(k+1);
                int z = x/3 + y/3*3;
                
                for(int i=0; i<9; i++){
                    if (t[0][x]&(1<<i)||t[1][y]&(1<<i)||t[2][z]&(1<<i))
                        continue;
                    t[0][x] |= (1 << i);
                    t[1][y] |= (1 << i);
                    t[2][z] |= (1 << i);
                    board[y][x] = i + '1';
                    if(f(k + 1))
                        return true;;
                    board[y][x] = '.';
                    t[0][x] &= ~(1 << i);
                    t[1][y] &= ~(1 << i);
                    t[2][z] &= ~(1 << i);                
                }
                return false;
            };
            f(0);
        }
    };
    

    38. Count and Say

    • 字符串
    class Solution {
    public:
        string countAndSay(int n) {
            string s("1");
            while(--n){
                string s2;
                for(auto it=s.begin(); it!=s.end();){
                    char ch = *it;
                    auto it2 = find_if(it, s.end(), [ch](char x){return x!=ch;});
                    int count = distance(it, it2);
                    s2 += '0'+count;
                    s2 += ch;
                    it = it2;
                }
                swap(s, s2);
            }
            return s;
        }
    };
    

    39. Combination Sum

    • 排列组合类型的问题,递归/回溯法
    • 该类某项可出现任意多次
    • 组合问题各组合升序排列
    class Solution {
    public:
        vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            vector<vector<int>> result;
            int n = candidates.size();
            int sum = 0;
            vector<int> item;
            function<void(int)> loop = [&](int i){
                if(sum>target)
                    return;
                if(sum==target){
                    result.push_back(item);
                    return;
                }
                for(int j=i;j<n;j++){
                    int x = candidates[j];
                    sum += x;
                    item.push_back(x);
                    loop(j);
                    sum -= x;
                    item.pop_back();
                }
            };
            loop(0);
            return result;
        }
    };
    

    40. Combination Sum II

    • 排列组合类的问题
    • 相比 39. Combination Sum 这题有重复元素
      • 重复运算可以用哈希表或者排序来处理
    class Solution {
    public:
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<vector<int>> result;
            sort(begin(candidates), end(candidates));
            const int n = candidates.size();
            vector<int> item;
            function<void(int,int)> loop = [&](int i, int sum){
                if(sum==target){
                    result.push_back(item);
                    return;
                }
                int y = -1;
                for(int j=i; j<n; j++){
                    int x = candidates[j];
                    if(x==y)
                        continue;
                    if(sum+x>target)
                        break;
                    item.push_back(x);
                    loop(j+1, sum+x);
                    item.pop_back();
                    y = x;
                }
            };
            loop(0, 0);
            return result;
        }
    };
    
    class Solution {
    public:
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            vector<vector<int>> result;
            sort(begin(candidates), end(candidates));
            const int n = candidates.size();
            vector<int> item;
            function<void(int,int)> loop = [&](int i, int sum){
                if(sum==target){
                    result.push_back(item);
                    return;
                }
                for(int j=i; j<n; j++){
                    int x = candidates[j];
                    if(j!=i && x==candidates[j-1])
                        continue;
                    if(sum+x>target)
                        break;
                    item.push_back(x);
                    loop(j+1, sum+x);
                    item.pop_back();
                }
            };
            loop(0, 0);
            return result;
        }
    };
    

    41. First Missing Positive

    • 题目限制挺具体的
    • 数组排列为 [1,2,3,...]
      • 满足 A[i]=i+1
      • 不满足则 iA[i]-1 交换
    class Solution {
    public:
        int firstMissingPositive(vector<int>& nums) {
            int n = nums.size();
            for(int i=0; i<n; i++)
                while(nums[i]>0 && nums[i]<=n && nums[i]!=nums[nums[i]-1])
                    swap(nums[i],nums[nums[i]-1]);
            for(int i=0; i<n; i++)
                if(nums[i]!=i+1)
                    return i+1;
            return n+1;
        }
    };
    

    42. Trapping Rain Water

    Array

    • 数组,双指针(下标)
    class Solution {
    public:
        int trap(vector<int>& height) {
            int i = 0, j = height.size()-1;
            int a = 0;
            int h = 0;
            while(i<j){
                if(height[i]<height[j]){
                    h = max(h, height[i]);
                    a += h - height[i];
                    i++;
                }else{
                    h = max(h, height[j]);
                    a += h - height[j];
                    j--;
                }
            }
            return a;
        }
    };
    

    43. Multiply Strings

    整数

    • 大数
    • 可以 4 个十进制位一个 32 位整型
    char* multiply(char* num1, char* num2) {
        int n1 = strlen(num1);
        int n2 = strlen(num2);
        int n3 = n1 + n2;
        char *num3 = (char*)calloc(n3+1, sizeof(char));
        for(int i=0; i<n1; i++){
            int a = num1[n1-i-1]-'0';
            int c = 0;
            for(int j=0; j<n2; j++){
                int b = num2[n2-j-1]-'0';
                int k = n3 - i - j - 1;
                c += a*b + num3[k];
                num3[k] = c%10;
                c /= 10;
            }
            num3[n3-n2-i-1] += c;
        }
        char *p = num3;
        for(int i=0; i<n3-1; i++){
            if(*p!=0)
                break;
            p++;
        }
        for(char *q=p; q<num3+n3; q++)
            *q += '0';
        return p;
    }
    

    44. Wildcard Matching

    • 字符串搜索
    • 通配符
    • 遇到星号时,记录下位置
    class Solution {
        bool isMatch(const char* s, const char* p){
            bool star = false;
            const char *ss=s, *pp=p;
            for(;;){    
                if(*s==0){
                    while(*p=='*')
                        p++;
                    return *p==0;
                }else if(*p=='?'){
                    if(*s==0)
                        return false;
                    s++, p++;       
                }else if(*p=='*'){
                    while(*++p=='*')
                        ;
                    star = true;
                    ss=s, pp=p;
                }else if(*p==*s){
                    s++, p++;
                }else if(star){
                    ss++;
                    s=ss, p=pp;
                }else{
                    return false;
                }
            }
        }
    public:
        bool isMatch(string s, string p) {
            return isMatch(s.c_str(), p.c_str());
        }
    };
    

    45. Jump Game II

    class Solution {
    public:
        int jump(vector<int>& nums) {
            int step = 0;
            int dist = 0;
            int arri = 0;
            for(int i=0; i<nums.size(); i++){
                if(i>arri){
                    arri = dist;
                    step += 1;
                }
                dist = max(dist , nums[i]+i);
            }
            return step;
        }
    };
    

    46. Permutations

    • 排列组合问题,求全排列
    • 递归/回溯
    class Solution {
    public:
        vector<vector<int>> permute(vector<int>& nums) {
            vector<vector<int>> result;
            function<void(int)> loop = [&](int i){
                if(i==nums.size()){
                    result.push_back(nums);
                    return;
                }
                for(int j=i; j<nums.size(); j++){
                    swap(nums[i],nums[j]);
                    loop(i+1);
                    swap(nums[i],nums[j]);
                }
            };
            loop(0);
            return result;
        }
    };
    

    47. Permutations II

    • 排列组合,全排列,有重复元素
    class Solution {
    public:
        vector<vector<int>> permuteUnique(vector<int>& nums) {
            vector<vector<int>> result;
            if(nums.empty())
                return result;
            unordered_map<int,int> h;
            for(int x: nums)
                h[x]++;
            vector<int> item;
            function<void(int)> loop = [&](int i){
                if(i==nums.size()){
                    result.push_back(item);
                    return;
                }
                for(auto p: h){
                    if(p.second){
                        item.push_back(p.first);
                        h[p.first]--;
                        loop(i+1);
                        h[p.first]++;
                        item.pop_back();
                    }
                }
            };
            loop(0);
            return result;
        }
    };
    

    48. Rotate Image

    • 二维数组中元素交换
    • 区分尺寸奇偶
    • 也可以做两次镜像。
    class Solution {
    public:
        void rotate(vector<vector<int>>& matrix) {
            int n = matrix.size();
            int s = n - 1;
            int e = n&1 ? n/2+1 : n/2;
            for(int i=0; i<e; i++)
                for(int j=0; j<n/2; j++){
                    int t = matrix[i][j];
                    matrix[i][j] = matrix[s-j][i];
                    matrix[s-j][i] = matrix[s-i][s-j];
                    matrix[s-i][s-j] = matrix[j][s-i];
                    matrix[j][s-i] = t;
                }
        }
    };
    

    49. Group Anagrams

    • 实现 group 函数
      可以利用哈希表或者排序,需要自行实现转化为key
    class Solution {
    public:
        vector<vector<string>> groupAnagrams(vector<string>& strs) {
            unordered_map<string,vector<string>> h;
            for(auto& s:strs){
                auto k = s;
                sort(begin(k),end(k));
                h[k].push_back(s);
            }
            vector<vector<string>> xs;
            for(auto it = h.begin(); it!=h.end(); ++it){
                vector<string> x;
                for(auto& e: it->second)
                    x.push_back(e);
                xs.push_back(x);
            }
            return xs;
        }
    };
    

    50. Pow(x, n)

    • 递归
    • 无符号数的位移
      • C 用操作数的类型
      • Java 里用操作符区分
    • 分奇偶
    • 有点小问题。

    要点
    位移:无符号位移高位补0,有符号位移补最高位。正数对应除以2。

    double myPow(double x, int n)
    {
        int neg = n<0;
        unsigned exp = neg ? -(unsigned)n : n;
        double y = 1;
        while(exp)
        {
            if(exp&1)
                y *= x;
            x *= x;
            exp >>= 1;
        }
        return neg ? 1/y : y;
    }
    
    class Solution {
    public:
        double myPow(double x, int n) {
            printf("n: %d\n",n);
            if(n==0)
                return 1;
            if(n==-1)
                return 1/x;
            double f = myPow(x,n>>1);
            return n%2 ? f*f*x : f*f;
        }
    };
    

    注意 C 的整数除法是向下取整的

    51. N-Queens

    • 八皇后
    • 求全部解
    • 回溯
    class Solution {
        vector<vector<string>> ans;
        int n;
        vector<bool> f1, f2, f3;
        vector<int> path;
        void f(int i){
            if(i==n){
                vector<string> item(n);
                for(int i=0; i<n ;i++){
                    string line(n, '.');
                    line[path[i]] = 'Q';
                    swap(item[i], line);
                }
                ans.push_back(item);
                return;
            }
            for(int j=0; j<n; j++){
                if(f1[j] || f2[i+j] || f3[n-i+j])
                    continue;
                path[i] = j;
                f1[j] = f2[i+j] = f3[n-i+j] = true;
                f(i+1);
                f1[j] = f2[i+j] = f3[n-i+j] = false;
            }
        }    
    public:
        vector<vector<string>> solveNQueens(int n) {
            this->n = n;
            f1.resize(n, false);
            f2.resize(2*n+1, false);
            f3.resize(2*n+1, false);
            path.resize(n, false);
            f(0);
            return ans;
        }
    };
    

    52. N-Queens II

    • 八皇后
      同上一题,返回解的个数
    class Solution {
        int count;
        int n;
        vector<bool> f1, f2, f3;
        void f(int i){
            if(i==n){
                count++;
                return;
            }
            for(int j=0; j<n; j++){
                if(f1[j] || f2[i+j] || f3[n-i+j])
                    continue;
                f1[j] = f2[i+j] = f3[n-i+j] = true;
                f(i+1);
                f1[j] = f2[i+j] = f3[n-i+j] = false;
            }
        }
    public:
        int totalNQueens(int n) {
            count = 0;
            this->n = n;
            f1.resize(n, false);
            f2.resize(2*n+1, false);
            f3.resize(2*n+1, false);
            f(0);
            return count;
        }
    };
    

    53. Maximum Subarray

    • 数组,动态规划
    • 挺有趣的一道题!
    class Solution {
    public:
        int maxSubArray(vector<int>& nums) {
            int m = INT_MIN;
            int d = 0;
            for(int x: nums){
                d = max(d+x, x);
                m = max(m, d);
            }
            return m;
        }
    };
    

    54. Spiral Matrix

    • 按照题意实现,小心不要越界
    /**
     * Note: The returned array must be malloced, assume caller calls free().
     */
    int* spiralOrder(int** matrix, int matrixRowSize, int matrixColSize) {
        int *result = (int*)malloc(sizeof(int)*(matrixRowSize*matrixColSize));
        int *s = result;
        int left = 0, right = matrixColSize-1;
        int top = 0, bottom = matrixRowSize-1;
        for(;left<=right && top<=bottom;){
            for(int i=left; i<=right; i++)
                *s++ = matrix[top][i];
            for(int i=top+1; i<=bottom; i++)
                *s++ = matrix[i][right];
            if(top==bottom || left==right)
                break;
            for(int i=right-1; i>=left; i--)
                *s++ = matrix[bottom][i];
            for(int i=bottom-1; i>=top+1; i--)
                *s++ = matrix[i][left];
            left++, right--, top++, bottom--;
        }
        return result;
    }
    

    55. Jump Game

    • 题目要求判断是否能抵达终点
    class Solution {
    public:
        bool canJump(vector<int>& nums) {
            int dist = 0;
            for(int i=0; i<=dist; i++){
                dist = max(dist, nums[i]+i);
                if(dist>=nums.size()-1)
                    return true;
            }
            return false;
        }
    };
    

    56. Merge Intervals

    /**
     * Definition for an interval.
     * struct Interval {
     *     int start;
     *     int end;
     *     Interval() : start(0), end(0) {}
     *     Interval(int s, int e) : start(s), end(e) {}
     * };
     */
    class Solution {
    public:
        vector<Interval> merge(vector<Interval>& intervals) {
            vector<Interval> result;
            sort(begin(intervals),end(intervals),
                [](Interval& a,Interval& b){return a.start<b.start;});
            for(auto& x: intervals){
                if(result.empty())
                    result.push_back(x);
                else if(x.start <= result.back().end)
                    result.back().end = max(x.end, result.back().end);
                else
                    result.push_back(x);
            }
            return result;
        }
    };
    

    57. Insert Interval

    • 一次移除一个元素不好。
    /**
     * Definition for an interval.
     * struct Interval {
     *     int start;
     *     int end;
     *     Interval() : start(0), end(0) {}
     *     Interval(int s, int e) : start(s), end(e) {}
     * };
     */
    class Solution {
    public:
        vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
            for(auto it = intervals.begin(); it!=intervals.end();){
                if(newInterval.end < it->start){
                    intervals.insert(it, newInterval);
                    return intervals;
                }else if(newInterval.start <= it->end){
                    newInterval.start = min(newInterval.start, it->start);
                    newInterval.end = max(newInterval.end, it->end);
                    it = intervals.erase(it);
                }else{
                    ++it;
                }
            }
            intervals.push_back(newInterval);
            return intervals;
        }
    };
    
    /**
     * Definition for an interval.
     * struct Interval {
     *     int start;
     *     int end;
     *     Interval() : start(0), end(0) {}
     *     Interval(int s, int e) : start(s), end(e) {}
     * };
     */
    class Solution {
    public:
        vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) {
            vector<Interval> result;
            auto it=intervals.begin();
            while(it!=intervals.end()){
                if(newInterval.end < it->start){
                    break;
                }else if(newInterval.start <= it->end){
                    newInterval.start = min(newInterval.start, it->start);
                    newInterval.end = max(newInterval.end, it->end);
                }else{
                    result.push_back(*it);
                }
                ++it;
            }
            result.push_back(newInterval);
            while(it!=intervals.end()){
                result.push_back(*it);
                ++it;
            }
            return result;
        }
    };
    

    58. Length of Last Word

    class Solution {
    public:
        int lengthOfLastWord(string s) {
            int y = 0;
            int count = 0;
            for(auto p = s.c_str();*p;p++){
                if(count!=0)
                    y = 0;
                if(*p==' '){
                    if(count!=0){
                        y = count;
                        count = 0;
                    }
                }else
                    count++;
            }
            return count ? count : y;
        }
    };
    

    59. Spiral Matrix II

    • 拿之前那题改一下,读变成写
    • 对照 54. Spiral Matrix
    /**
     * Return an array of arrays.
     * Note: The returned array must be malloced, assume caller calls free().
     */
    int** generateMatrix(int n) {
        int **matrix = (int**)malloc(sizeof(int*)*n);
        for(int i=0; i<n ;i++)
            matrix[i] = (int*)malloc(sizeof(int)*n);
        int count = 1;
        int left = 0, right = n-1;
        int top = 0, bottom = n-1;
        for(;left<=right && top<=bottom;){
            for(int i=left; i<=right; i++)
                matrix[top][i] = count++;
            for(int i=top+1; i<=bottom; i++)
                matrix[i][right] = count++;
            if(top==bottom || left==right)
                break;
            for(int i=right-1; i>=left; i--)
                matrix[bottom][i] = count++;
            for(int i=bottom-1; i>=top+1; i--)
                matrix[i][left] = count++;
            left++, right--, top++, bottom--;
        }
        return matrix;
    }
    

    60. Permutation Sequence

    • 排列组合
    • n 个元素有 n! 个排列,n-1 个元素有 (n-1)! 个排列
    • 取模/整数除法运算是对从 0 开始的整数
    char* getPermutation(int n, int k) {
        char *s = (char*)malloc(sizeof(char)*(n+1));
        s[n] = 0;
        for(int i=0; i<n; i++)
            s[i] = '1' + i;
        int a = 1;
        for(int i=2; i<n; i++)
            a *= i;
        k--;
        for(int i=0; k; i++){
            int j = k/a;
            char t = s[i+j];
            for(int p=i+j; p>i; p--)
                s[p] = s[p-1];
            s[i] = t;
            k %= a;
            a /= n-1-i;
        }
        return s;
    }
    

    61. Rotate List

    • 链表
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* rotateRight(ListNode* head, int k) {
            if(!head || !k)
                return head;
            ListNode** p = &head;
            int n = 0;
            while(*p){
                n++;
                p = &(*p)->next;
            }
            *p = head;
            for(int c=n-k%n; c--;)
                p = &(*p)->next;
            head = *p;
            *p = NULL;
            return head;
        }
    };
    

    62. Unique Paths

    • 排列组合
    • 动态规划
    int nchoosek(int n, int k){
        long long res = 1;
        for(int i=0;i<k;i++)
            res *= n-i;
        for(int i=1;i<=k;i++)
            res /= i;
        return res;
    }
    int uniquePaths(int m, int n) {
        return nchoosek(m+n-2, (m<n ? m : n)-1);
    }
    

    63. Unique Paths II

    • 动态规划,挺有趣的一道题
    int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridRowSize, int obstacleGridColSize) {
        int *d = (int*)malloc(sizeof(int)*obstacleGridColSize);
        memset(d,0,sizeof(int)*obstacleGridColSize);
        d[0] = 1 - obstacleGrid[0][0];
        for(int y=0; y<obstacleGridRowSize; y++){
            d[0] = d[0] ? 1-obstacleGrid[y][0] : 0;
            for(int x=1; x<obstacleGridColSize; x++)
                d[x] = obstacleGrid[y][x] ? 0 : (d[x-1]+d[x]);
        }
        return d[obstacleGridColSize-1];
    }
    

    64. Minimum Path Sum

    • 动态规划
    • 递推关系 D[i][j] = grid[i][j] + min(D[i-1][j], D[i][j-1])
    int minPathSum(int** grid, int gridRowSize, int gridColSize) {
        int D[gridColSize];
        D[0] = grid[0][0];
        for(int i=1; i<gridColSize; i++)
            D[i] = grid[0][i] + D[i-1];
        for(int i=1; i<gridRowSize; i++){
            D[0] += grid[i][0];
            for(int j=1; j<gridColSize; j++)
                D[j] = grid[i][j] + (D[j]<=D[j-1] ? D[j] : D[j-1]);
        }
        return D[gridColSize-1];
    }
    

    65. Valid Number

    • 状态机,正则表达式
    bool isNumber(char* s) {
        char* e;
        double a = strtof(s, &e);
        if(e==s)
            return false;
        while(isspace(*e))
            e++;
        return *e==0;
    }
    

    66. Plus One

    • 挺有趣的题,大数和排列组合的题目中会用到。
    class Solution {
    public:
        vector<int> plusOne(vector<int>& digits) {
            for(int i=digits.size()-1; i>=0; i--){
                if(digits[i]<9){
                    digits[i]++;
                    return digits;
                }
                digits[i] = 0;
            }
            digits.insert(digits.begin(), 1);
            return digits;
        }
    };
    
    class Solution {
    public:
        vector<int> plusOne(vector<int>& digits) {
            vector<int> result(digits.size());
            int carry = 1;
            for(int i=digits.size()-1; i>=0; i--){
                int digit = digits[i] + carry;
                result[i] = digit%10;
                carry = digit/10;
            }
            if(carry)
                result.insert(result.begin(), carry);
            return result;
        }
    };
    

    67. Add Binary

    • 大数
    class Solution {
    public:
        string addBinary(string a, string b) {
            string c;
            int m = a.size(), n = b.size();
            int carry = 0;
            int i = m-1, j = n-1;
            for(int k=0, e=max(m,n); k<e; k++){
                carry += i>=0 && a[i--]=='1';
                carry += j>=0 && b[j--]=='1';
                c += '0'+(carry&1);
                carry >>= 1;
            }
            if(carry)
                c += '1';
            reverse(c.begin(), c.end());
            return c;
        }
    };
    

    68. Text Justification

    • 细节略多
    class Solution {
    public:
        vector<string> fullJustify(vector<string>& words, int maxWidth) {
            vector<string> ans;
            int start = 0;
            int size = 0;
            for(int i=0; i<words.size(); i++){
                string line;
                size += words[i].size();
                int c = i - start - 1;
                if(size+c>=maxWidth){
                    size = words[i].size();
                    int space = maxWidth;
                    for(int j=start; j<i; j++)
                        space -= words[j].size();
                    line += words[start++];
                    if(c==0){
                        line.append(space, ' ');
                    }else{
                        for(; start<i; c--){
                            int r = space/c+!!(space%c);
                            line.append(r, ' ');
                            space -= r;
                            line += words[start++];
                        }
                    }
                    ans.push_back(line);
                }
            }
            if(start<words.size()){
                string line;
                for(int i=start;i<words.size(); i++){
                    if(!line.empty())
                        line += ' ';
                    line += words[i];
                }
                line.append(maxWidth-line.size(), ' ');
                ans.push_back(line);
            }
            return ans;
        }
    };
    

    69. Sqrt(x)

    • 二分法
    • 牛顿法
    int mySqrt(int x) {
        int a = 1, b = x;
        while(a<=b){
            int c = (a+b)/2;
            if(c==x/c)
                return c;
            else if(c<x/c)
                a = c+1;
            else
                b = c-1;
        }
        return b;
    }
    

    70. Climbing Stairs

    • 斐波那契数列
      • 下标为台阶个数,值为路径个数
      • 满足 a_n = a{n-1}+a{n-1}, a_1=1, a_2=2
    int climbStairs(int n) {
        int a = 0, b = 1;
        while(n--){
            int c = a+b;
            a = b, b = c;
        }
        return b;
    }
    

    71. Simplify Path

    class Solution {
    public:
        string simplifyPath(string path) {
            vector<string> stack;
            auto it = path.begin();
            while(it!=path.end()){
                ++it;
                auto end = find(it,path.end(),'/');
                string s(it, end);
                if(s==".."){
                    if(!stack.empty())
                        stack.pop_back();
                }else if(!s.empty() && s!="."){
                    stack.push_back(s);
                }
                it = end;
            }
            if(stack.empty())
                return "/";
            string result;
            for(auto& s: stack){
                result += "/";
                result += s;
            }
            return result;
        }
    };
    

    72. Edit Distance

    DP

    • 编辑距离
    • 动态规划,按字符
      • 相等 d[i][j] = d[i-1][j-1]
      • 替换 d[i][j] = d[i-1][j-1]+1
      • 添加 d[i][j] = d[i][j-1]+1
      • 删除 d[i][j] = d[i-1][j]+1
    • 写成递归的形式或迭代的形式

    动规

    class Solution {
    public:
        int minDistance(string word1, string word2) {
            vector<int> d(word2.size()+1);
            for(int i=0; i<=word2.size(); i++)
                d[i] = i;
            for(int i=1; i<=word1.size(); i++){
                int c = d[0];
                d[0] = i;
                for(int j=1; j<=word2.size() ;j++){
                    int t = d[j];
                    if(word1[i-1]==word2[j-1])
                        d[j] = c;
                    else
                        d[j] = min(c, min(d[j-1],d[j])) + 1;
                    c = t;
                }
            }
            return d[word2.size()];
        }
    };
    

    递归

    class Solution {
    public:
        int minDistance(string word1, string word2) {
            map<pair<int,int>,int> h;
            function<int(int,int)> d = [&](int i, int j)->int{
                if(h.count({i,j}))
                    return h[{i,j}];
                if(i==word1.size())
                    return word2.size()-j;
                if(j==word2.size())
                    return word1.size()-i;
                int a = (word1[i]==word2[j] ? 0: 1)+d(i+1, j+1);
                int b = 1 + d(i+1, j);
                int c = 1 + d(i, j+1);
                return h[{i,j}] = min(a, min(b, c));
            };
            return d(0,0);
        }
    };
    

    73. Set Matrix Zeroes

    • 为了不另开空间,第一行第一列先扫一遍,然后用来做记录。
    void setZeroes(int** matrix, int matrixRowSize, int matrixColSize) {
        int row = 1, col = 1;
        for(int i=0;i<matrixRowSize;i++)
            if(matrix[i][0]==0){
                col = 0;
                break;
            }
        for(int i=0; i<matrixColSize; i++)
            if(matrix[0][i]==0){
                row = 0;
                break;
            }
        for(int i=0;i<matrixRowSize;i++)
            for(int j=0; j<matrixColSize; j++)
                if(matrix[i][j]==0)
                    matrix[i][0] = matrix[0][j] = 0;
        for(int i=1;i<matrixRowSize;i++)
            if(matrix[i][0]==0)
                for(int j=0;j<matrixColSize;j++)
                    matrix[i][j] = 0;
        for(int i=1;i<matrixColSize;i++)
            if(matrix[0][i]==0)
                for(int j=0;j<matrixRowSize;j++)
                    matrix[j][i] = 0;                
        if(row==0)
            for(int i=0; i<matrixColSize; i++)
                matrix[0][i] = 0;
        if(col==0)
            for(int i=0;i<matrixRowSize;i++)
                matrix[i][0] = 0;
    }
    

    74. Search a 2D Matrix

    • 二分查找
    • 这题直接按照一维就可以了。
    bool searchMatrix(int** matrix, int m, int n, int target) {
        int a = 0, b = m*n;
        while(a<b){
            int c = (a+b)/2;
            int mid = matrix[c/n][c%n];
            if(mid==target)
                return true;
            else if(mid<target)
                a = c + 1;
            else
                b = c;
        }
        return false;
    }
    

    75. Sort Colors

    • 题目要求不要用排序函数
    • 这道题正好只有三个元素要排序
      • 数组遍历过程中往两端插入
    class Solution {
    public:
        void sortColors(vector<int>& nums) {
            int l = 0, r = nums.size()-1;
            for(int i=l; i<=r;){
                switch(nums[i]){
                    case 0:
                        swap(nums[i], nums[l++]);
                    case 1:
                        i++;
                        break;
                    case 2:
                        swap(nums[i], nums[r--]);
                        break;
                }
            }
        }
    };
    

    76. Minimum Window Substring

    • 双指针
    • 收缩比扩展好实现
    class Solution {
    public:
        string minWindow(string s, string t) {
            int start = 0;
            int size = INT_MAX;
            int h[128] = {0};
            for(char ch: t)
                h[ch]++;
            int d[128] = {0};
            int count = 0;
            for(int i=0, j=0;i<s.size(); i++){
                if(h[s[i]]){
                    d[s[i]]++;
                    if(d[s[i]]<=h[s[i]])
                        count++;
                    if(count==t.size()){
                        while(d[s[j]]>h[s[j]] || h[s[j]]==0)
                            d[s[j++]]--;
                        if(i-j+1<size){
                            size = i-j+1;
                            start = j;
                        }
                    }
                }
            }
            return size==INT_MAX ? "" : s.substr(start,size);
        }
    };
    

    77. Combinations

    • 排列组合问题,组合是全排列中升序的排列
    • 该题的序列是从 1 开始的
    class Solution {
    public:
        vector<vector<int>> combine(int n, int k) {
            vector<vector<int>> result;
            vector<int> item(k);
            function<void(int,int)> loop = [&](int i, int x){
                if(i==k){
                    result.push_back(item);
                    return;
                }
                for(int j=x;j<=n;j++){
                    item[i] = j;
                    loop(i+1,j+1);
                }
            };
            loop(0, 1);
            return result;
        }
    };
    

    78. Subsets

    • 排列组合问题
    • 二进制位表示集合
    class Solution {
    public:
        vector<vector<int>> subsets(vector<int>& nums) {
            vector<vector<int>> result;
            for(int i=0, n=(1<<nums.size()); i<n; i++){
                vector<int> item;
                for(int j=0; j<nums.size(); j++)
                    if((i>>j)&1)
                        item.push_back(nums[j]);
                result.push_back(item);
            }
            return result;
        }
    };
    

    79. Word Search

    • 图的深度优先搜索
    • 本题中要求路径无环,矩阵按行储存
    bool f(char** board, int boardRowSize, int boardColSize, char* word,int x,int y,bool** visited) {
        if(*word==0)
            return true;
        if(x<0 || x>= boardColSize || y<0 || y>=boardRowSize)
            return false;
        if(visited[y][x])
            return false;
        if(board[y][x]==*word){
            visited[y][x] = true;
            bool result = (
                f(board, boardRowSize, boardColSize, word+1, x-1, y, visited)||
                f(board, boardRowSize, boardColSize, word+1, x+1, y, visited)||
                f(board, boardRowSize, boardColSize, word+1, x, y-1, visited)||
                f(board, boardRowSize, boardColSize, word+1, x, y+1, visited)
            );
            visited[y][x] = false;
            return result;
        }
        return false;
    }
    bool exist(char** board, int boardRowSize, int boardColSize, char* word) {
        bool **visited = (bool**)malloc(sizeof(bool*)*boardRowSize);
        for(int i=0;i<boardRowSize;i++)
            visited[i] = (bool*)calloc(1, sizeof(bool*)*boardColSize);
        for(int y=0; y<boardRowSize; y++)
            for(int x=0; x<boardColSize; x++)
                if(f(board, boardRowSize, boardColSize, word, x, y, visited))
                    return true;
        return false;
    }
    

    80. Remove Duplicates from Sorted Array II

    • 有序数组,重复元素相邻
    int removeDuplicates(int* nums, int numsSize) {
        int *p = nums;
        int item = -1, count = 0;
        for(int i=0; i<numsSize; i++){
            if(nums[i]==item){
                if(count==2)
                    continue;
                count++;
            }else{
                item = nums[i];
                count = 1;
            }
            *p++=nums[i];
        }
        return p - nums;
    }
    

    81. Search in Rotated Sorted Array II

    Search

    • 二分搜索,旋转后的有序数组
    • 比之前的题目多了:有重复元素
    bool search(int* A, int n, int target) {
        int a = 0, b = n;
        while(a<b){
            int c = a+(b-a)/2;
            if(A[c]==target){
                return true;
            }else if(A[a]==A[c]){
                a++;
            }else if(A[a]<A[c]){
                if(A[a]<=target && target<A[c])
                    b = c;
                else
                    a = c + 1;
            }else{
                if(A[c]<target && target<=A[b-1])
                    a = c + 1;
                else
                    b = c;
            }
        }
        return false;  
    }
    

    82. Remove Duplicates from Sorted List II

    • 链表节点操作
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* deleteDuplicates(ListNode* head) {
            ListNode** p = &head;
            while(*p){
                ListNode* q = (*p)->next; 
                if(q && q->val==(*p)->val){
                    q = q->next;
                    while(q && q->val==(*p)->val)
                        q = q->next;
                    *p = q;
                }else
                    p = &(*p)->next;
            }
            return head;
        }
    };
    

    83. Remove Duplicates from Sorted List

    • 前面有题目是数组,这次是链表。
    class Solution {
    public:
        ListNode* deleteDuplicates(ListNode* head) {
            for(auto p = head; p; p = p->next){
                auto q = p->next;
                while(q && q->val==p->val)
                    q = q->next;
                p->next = q;
            }
            return head;
        }
    };
    

    84. Largest Rectangle in Histogram

    • 最大矩形
    • Stack,大于则入栈,小于则合并,最后合并全部。
    class Solution {
    public:
        int largestRectangleArea(vector<int>& heights) {
            int ans = 0;
            stack<int> s;
            heights.push_back(0);
            for(int i=0; i<heights.size();i++){
                while(!s.empty() && heights[i]<=heights[s.top()]){
                    int j = s.top();
                    s.pop();
                    int width = s.empty() ? i : i-s.top()-1;
                    ans = max(ans, heights[j]*width);
                }
                s.push(i);
            }
            return ans;
        }
    };
    

    85. Maximal Rectangle

    • 84. Largest Rectangle in Histogram 改改
    • 也可以用动态规划
    class Solution {
    public:
        int maximalRectangle(vector<vector<char>>& matrix) {
            int row = matrix.size();
            if(row==0)
                return 0;
            int col = matrix[0].size();
            vector<int> heights(col+1, 0);
            int ans = 0;
            for(int y=0;y<row; y++){
                for(int x=0; x<col; x++)
                    heights[x] = matrix[y][x]=='1' ? heights[x] + 1 : 0;
                stack<int> s;
                for(int i=0; i<heights.size();i++){
                    while(!s.empty() && heights[i]<=heights[s.top()]){
                        int j = s.top();
                        s.pop();
                        int width = s.empty() ? i : i-s.top()-1;
                        ans = max(ans, heights[j]*width);
                    }
                    s.push(i);
                }
            }
            return ans;
        }
    };
    

    86. Partition List

    • 链表节点操作
    • 链表追加,可以用一个空的头节点
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    typedef struct ListNode Node;
    void list_append(Node*** tail, Node* node){
        **tail = node;
        *tail = &node->next;
    }
    struct ListNode* partition(struct ListNode* head, int x) {
        Node* list1 = NULL;
        Node* list2 = NULL;
        Node** append1 = &list1;
        Node** append2 = &list2;
        for(; head; head=head->next)
            list_append(head->val<x ? &append1 : &append2, head);
        list_append(&append2, NULL);
        list_append(&append1, list2);
        return list1;
    }
    

    87. Scramble String

    DP

    • 动态规划
    class Solution {
    public:
        bool isScramble(string s1, string s2) {
            map<tuple<int,int,int>,bool> m;
            function<bool(int,int,int)> f = [&](int a, int b, int c){
                //printf("%d %d %d\n",a,b,c);
                if(c==1)
                    return s1[a]==s2[b];
                auto t = make_tuple(a, b, c);
                auto it = m.find(t);
                if(it!=m.end())
                    return it->second;
                for(int i=1; i<c; i++){
                    if(f(a,b,i) && f(a+i,b+i,c-i))
                        return m[t] = true;
                    if(f(a,b+c-i,i) && f(a+i,b,c-i))
                        return m[t] = true;
                }
                return m[t] = false; 
            } ;
            if(s1.size()!=s2.size())
                return true;
            return f(0,0,s1.size());
        }
    };
    

    88. Merge Sorted Array

    • 有序数组归并
    • 这题是在数组中插入另一个数组
    void merge(int* nums1, int m, int* nums2, int n) {
        int* s = nums1 + m + n-1;
        int i = m-1, j = n-1;
        while(i>=0 && j>=0)
            *s-- = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--];
        while(j>=0)
            *s-- = nums2[j--];
    }
    

    89. Gray Code

    class Solution {
    public:
        vector<int> grayCode(int n) {
            vector<int> ans;
            for(int i=0,e=1<<n; i<e; i++)
                ans.push_back((i>>1)^i);
            return ans;
        }
    };
    

    90. Subsets II

    • 递归 + 回溯
      • 或者自行用栈实现
    • 先统计重复元素个数
    class Solution {
    public:
        vector<vector<int>> subsetsWithDup(vector<int>& nums) {
            vector<vector<int>> result;
            unordered_map<int,int> h;
            for(int x: nums)
                h[x]++;
            vector<int> keys;
            for(auto p: h)
                keys.push_back(p.first);
            vector<int> stack;
            stack.push_back(-1);
            while(!stack.empty()){
                int n = stack.size();
                stack.back()++;
                if(stack.back()>h[keys[n-1]]){
                    stack.pop_back();
                }else if(n==keys.size()){
                    vector<int> item;
                    for(int j=0; j<n; j++)
                        for(int k=0; k<stack[j]; k++)
                            item.push_back(keys[j]);
                    result.push_back(item);
                }else{
                    stack.push_back(-1);
                }
            }
            return result;
        }
    };
    

    91. Decode Ways

    • 回溯,动态规划
    class Solution {
    public:
        int numDecodings(string s) {
            int a = 1, b = 1, c = 0;
            char p = 0;
            for(char ch: s){
                c = 0;
                if(ch!='0')
                    c += b;
                if((p=='2'&&ch<='6')||(p=='1'))
                    c += a;
                p = ch;
                a = b;
                b = c;
            }
            return c;
        }
    };
    

    92. Reverse Linked List II

    • 挺有趣的一道题
    • 在逆置链表的基础上改一下
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
        ListNode* reverse(ListNode* head){
            ListNode* prev = NULL;
            while(head){
                auto next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            return prev;
        }
    public:
        ListNode* reverseBetween(ListNode* head, int m, int n) {
            ListNode** p = &head;
            for(int i=1; i<m; i++)
                p = &(*p)->next;
            ListNode* first = *p;
            ListNode* last = *p;
            for(int i=m; i<n; i++)
                last = last->next;
            ListNode* next = last->next;        
            last->next = NULL;
            *p = reverse(*p);
            first->next = next;
            return head;
        }
    };
    

    93. Restore IP Addresses

    • 回溯
    class Solution {
    public:
        vector<string> restoreIpAddresses(string s) {
            vector<string> result;
            vector<int> path;
            function<void(int,int)> f = [&](int i, int x){
                if(i==s.size()){
                    if(path.size()==4 && x==0){
                        char b[s.size()+4];
                        sprintf(b,"%d.%d.%d.%d",path[0],path[1],path[2],path[3]);
                        result.push_back(b);
                    }
                    return;
                }
                int y = x*10 + (s[i]-'0');
                if(y>=256)
                    return;
                if(y!=0)
                    f(i+1, y);
                if(path.size()<4){
                    path.push_back(y);
                    f(i+1, 0);
                    path.pop_back();
                }
            };
            f(0, 0);
            return result;
        }
    };
    

    94. Binary Tree Inorder Traversal

    • 重点问题!
    • 二叉树中序遍历
      • LNR,根节点在左右节点之间访问
      • 对排序二叉树树得到升序序列
    • 递归,非递归
      • 先访问最左边的节点
      • 记录出栈顺序
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> inorderTraversal(TreeNode* root) {
            vector<int> result;
            stack<TreeNode*> s;
            TreeNode* p = root;
            while(p || !s.empty()){
                if(p){
                    s.push(p);
                    p = p->left;
                }else{
                    p = s.top();
                    s.pop();
                    result.push_back(p->val);
                    p = p->right;
                }
            }
            return result;
        }
    };
    

    95. Unique Binary Search Trees II

    • 挺有趣的题目
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        vector<TreeNode*> generateTrees(int begin, int end) {
            vector<TreeNode*> result;
            if(begin==end)
                result.push_back(NULL);
            else
                for(int i=begin; i<end; i++)
                    for(auto left: generateTrees(begin,i))
                        for(auto right: generateTrees(i+1, end)){
                            auto node = new TreeNode(i);
                            node->left = left;
                            node->right = right;
                            result.push_back(node);
                        }
            return result;
        }
    public:
        vector<TreeNode*> generateTrees(int n) {
            if(n==0)
                return {};
            return generateTrees(1, n+1);
        }
    };
    

    96. Unique Binary Search Trees

    • 动态规划
    • 以上一题为基础
    • 选一个根节点,个数为左子树乘以右子树,然后求和
    class Solution {
    public:
        int numTrees(int n) {
            vector<int> f(n+1);
            f[0] = f[1] = 1;
            for(int i=2; i<=n; i++)
                for(int j=1; j<=i; j++)
                    f[i] += f[j-1]*f[i-j];
            return f[n];
        }
    };
    

    97. Interleaving String

    DP

    动态规划

    class Solution {
    public:
        bool isInterleave(string s1, string s2, string s3) {
            int l1 = s1.size();
            int l2 = s2.size();
            int l3 = s3.size();
            if(l1+l2!=l3)
                return false;
            vector<bool> d(l1+1);
            d[0] = true;
            for(int i=0; i<l1; i++)
                d[i+1] = d[i] && s1[i]==s3[i];
            for(int i=0; i<l2; i++){
                d[0] = d[0] && s2[i]==s3[i];
                for(int j=0; j<l1; j++){
                    char c = s3[i+j+1];
                    d[j+1] = (d[j] && s1[j]==c) || (d[j+1] && s2[i]==c);
                }
            }
            return d[l1];
        }
    };
    

    98. Validate Binary Search Tree

    • 检查是否为二叉搜索树
      • 节点满足大小升序关系
    • 二叉树中序遍历
      • 递归,非递归实现
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        int *prev;
        bool f(TreeNode* node){
            if(!node)
                return true;
            if(!f(node->left))
                return false;
            if(prev && *prev>=node->val)
                return false;
            prev = &node->val;
            if(!f(node->right))
                return false;
            return true;
        }
    public:
        bool isValidBST(TreeNode* root) {
            prev = NULL;
            return f(root);
        }
    };
    

    99. Recover Binary Search Tree

    • 二叉树搜索树中序遍历得到升序序列
    • 用递归不符合题目 O(1) 空间的目标
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        TreeNode* prev = NULL;
        TreeNode* broken = NULL;
        TreeNode* broken2 = NULL;
        bool f(TreeNode* node){
            if(!node)
                return false;
            if(f(node->left))
                return true;
            if(prev && prev->val>node->val){
                if(broken==NULL){
                    broken = prev;
                    broken2 = node;
                }else{
                    broken2 = node;
                    return true;
                }
            }
            prev = node;
            if(f(node->right))
                return true;
            return false;
        }
    public:
        void recoverTree(TreeNode* root) {
            f(root);
            swap(broken->val, broken2->val);
        }
    };
    

    100. Same Tree

    • 二叉树
    • 递归遍历
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
    bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
        if(p && q)
            return (
                p->val == q->val && 
                isSameTree(p->left, q->left) &&
                isSameTree(p->right, q->right)
            );
        else
            return p==NULL && q==NULL;
    }
    

    101. Symmetric Tree

    • 题目要求两种解法

    递归

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
     
    bool isMirror(struct TreeNode* t1, struct TreeNode* t2){
        if(!t1 && !t2)
            return true;
        if(!t1 || !t2)
            return false;
        if(t1->val!=t2->val)
            return false;
        return isMirror(t1->left, t2->right) && isMirror(t1->right, t2->left);
    }
    bool isSymmetric(struct TreeNode* root) {
        return root ? isMirror(root->left, root->right) : true;
    }
    

    迭代

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        bool isSymmetric(TreeNode* root) {
            if(!root)
                return true;
            stack<TreeNode*> q;
            q.push(root->left);
            q.push(root->right);
            while(!q.empty()){
                auto a = q.top();
                q.pop();
                auto b = q.top();
                q.pop();
                if(!a && !b)
                    continue;
                if(!a || !b)
                    return false;
                if(a->val!=b->val)
                    return false;
                q.push(a->left);
                q.push(b->right);
                q.push(b->left);
                q.push(a->right);
            }
            return true;
        }
    };
    

    这题 LeetCode 目前给的答案不太好

    102. Binary Tree Level Order Traversal

    • 二叉树层次遍历
    • 队列,广度优先
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> levelOrder(TreeNode* root) {
            vector<vector<int>> result;
            vector<int> line;
            queue<TreeNode*> q;
            q.push(root);
            q.push(NULL);
            for(;;){
                TreeNode* node = q.front();
                q.pop();
                if(node){
                    line.push_back(node->val);
                    if(node->left)
                        q.push(node->left);
                    if(node->right)
                        q.push(node->right);
                }else{
                    if(line.empty())
                        break;
                    result.push_back(line);
                    line.clear();
                    q.push(NULL);
                }
            }
            return result;
        }
    };
    

    103. Binary Tree Zigzag Level Order Traversal

    • 二叉树层次遍历
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
            vector<vector<int>> result;
            queue<TreeNode*> q;
            bool r = false;
            if(root)
                q.push(root);
            while(!q.empty()){
                vector<int> item;
                int n = q.size();
                while(n--){
                    auto node = q.front();
                    q.pop();
                    item.push_back(node->val);
                    if(node->left)
                        q.push(node->left);
                    if(node->right)
                        q.push(node->right);
                }
                if(r)
                    reverse(item.begin(), item.end());
                result.push_back(item);
                r = !r;
            }
            return result;
        }
    };
    

    104. Maximum Depth of Binary Tree

    • 二叉树遍历
    class Solution {
    public:
        int maxDepth(TreeNode* root) {
            if(root==NULL)
                return 0;
            return 1 + max(maxDepth(root->left),maxDepth(root->right));        
        }
    };
    

    105. Construct Binary Tree from Preorder and Inorder Traversal

    • 二叉树遍历,逆
    • 递归
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
            function<TreeNode*(int,int,int)> build = [&](int i, int j, int n)->TreeNode*{
                if(n==0)
                    return nullptr;
                int val = preorder[i];
                int left_size = find(inorder.begin()+j,inorder.end(),val)-inorder.begin()-j;
                int right_size = n-left_size-1;
                cout<<val<<left_size<<right_size<<endl;
                auto node = new TreeNode(val);
                node->left = build(i+1, j, left_size);
                node->right = build(i+left_size+1, j+left_size+1, right_size);
                return node;
            };
            return build(0,0, preorder.size());
        }
    };
    

    106. Construct Binary Tree from Inorder and Postorder Traversal

    • 同上
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
    int find(int *xs, int x){
        for(int i=0;;i++)
            if(xs[i]==x)
                return i;
    }
    struct TreeNode *build(int *inorder,int *postorder,int n){
        if(n==0)
            return NULL;
        int value = postorder[n-1];
        int left_length = find(inorder, value);
        int right_length = n - left_length - 1;
        struct TreeNode *node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
        node->val = value;
        node->left = build(inorder, postorder, left_length);
        node->right = build(inorder+left_length+1, postorder+left_length, right_length);
        return node;
    }
    struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize) {
        return build(inorder, postorder, inorderSize);
    }
    

    107. Binary Tree Level Order Traversal II

    • 二叉树
    • 广度优先搜索,层次遍历
    • 这题要求输出逆序
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> levelOrderBottom(TreeNode* root) {
            vector<vector<int>> result;
            queue<TreeNode*> q;
            if(root)
                q.push(root);
            while(!q.empty()){
                int n = q.size();
                vector<int> item;
                while(n--){
                    auto node = q.front();
                    q.pop();
                    item.push_back(node->val);
                    if(node->left)
                        q.push(node->left);
                    if(node->right)
                        q.push(node->right);
                }
                result.push_back(item);
            }
            reverse(result.begin(), result.end());
            return result;
        }
    };
    

    108. Convert Sorted Array to Binary Search Tree

    • 二分搜索
    • 递归,构建搜索树
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
    struct TreeNode* sortedArrayToBST(int* nums, int numsSize) {
        if(numsSize==0)
            return NULL;
        typedef struct TreeNode Node;
        Node* node = (Node*)malloc(sizeof(Node));
        node->val = nums[numsSize/2];
        node->left = sortedArrayToBST(nums, numsSize/2);
        node->right = sortedArrayToBST(nums+numsSize/2+1, numsSize-numsSize/2-1);
        return node;
    }
    

    109. Convert Sorted List to Binary Search Tree

    • 递归
    • 按中序遍历从有序序列中取元素
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        TreeNode* f(ListNode** node, int a, int b){
            if(a>=b)
                return NULL;
            int c = a+(b-a)/2;
            auto tree_node = new TreeNode(-1);
            tree_node->left = f(node, a, c);
            tree_node->val = (*node)->val;
            *node = (*node)->next;
            tree_node->right = f(node, c+1, b);
            return tree_node;
        }
    public:
        TreeNode* sortedListToBST(ListNode* head) {
            int n = 0;
            for(auto p=head; p; p=p->next)
                n++;
            return f(&head, 0, n);
        }
    };
    

    110. Balanced Binary Tree

    • 递归+短路
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        bool isBalanced(TreeNode* root, int* depth) {
            if(!root){
                *depth = 0;
                return true;
            }
            int left_depth, right_depth;
            if(!isBalanced(root->left, &left_depth))
                return false;
            if(!isBalanced(root->right, &right_depth))
                return false;
            if(abs(left_depth-right_depth)>1)
                return false;
            *depth = max(left_depth, right_depth)+1;
            return true;
        }    
    public:
        bool isBalanced(TreeNode* root) {
            int depth;
            return isBalanced(root, &depth);
        }
    };
    

    111. Minimum Depth of Binary Tree

    • 二叉树
    • 递归
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int minDepth(TreeNode* root) {
            if(root==nullptr)
                return 0;
            if(root->left==nullptr)
                return minDepth(root->right)+1;
            if(root->right==nullptr)
                return minDepth(root->left)+1;
            return min(minDepth(root->left), minDepth(root->right)) + 1;
        }
    };
    

    112. Path Sum

    • 二叉树,短路
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
    bool hasPathSum(struct TreeNode* root, int sum) {
        if(!root)
            return false;
        sum -= root->val;
        if(!root->left && !root->right)
            return sum==0;
        return hasPathSum(root->left, sum) || hasPathSum(root->right, sum);
    }
    

    113. Path Sum II

    • 二叉树,叶节点,路径
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<vector<int>> pathSum(TreeNode* root, int sum) {
            vector<vector<int>> result;
            vector<int> path;
            function<void(TreeNode*,int)> f = [&](TreeNode* node,int sum){
                if(!node)
                    return;
                sum -= node->val;
                path.push_back(node->val);
                if(!node->left && !node->right){
                    if(sum==0)
                        result.push_back(path);
                }else{
                    f(node->left, sum);
                    f(node->right, sum);
                }
                path.pop_back();
            };
            f(root, sum);
            return result;
        }
    };
    

    114. Flatten Binary Tree to Linked List

    Tree

    • 先序
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        TreeNode* f(TreeNode* node,TreeNode* tail){
            if(!node)
                return tail;
            node->right = f(node->left, f(node->right, tail));
            node->left = NULL;
            return node;
        }
    public:
        void flatten(TreeNode* root) {
            f(root, NULL);
        }
    };
    

    115. Distinct Subsequences

    • 动态规划
    • 返回子序列个数
      • 递归前缀的部分
    class Solution {
    public:
        int numDistinct(string s, string t) {
            vector<int> d(t.size()+1, 0);
            d[0] = 1;
            for(int i=0; i<s.size(); i++)
                for(int j=t.size(); j>0; j--)
                    if(s[i]==t[j-1])
                        d[j] += d[j-1];
            return d[t.size()];
        }
    };
    

    116. Populating Next Right Pointers in Each Node

    • 这题的输入限定为满二叉树(最后一层也是满的的完全二叉树)。
    • 题目要求不开空间,
    /**
     * Definition for binary tree with next pointer.
     * struct TreeLinkNode {
     *  int val;
     *  TreeLinkNode *left, *right, *next;
     *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void connect(TreeLinkNode *root) {
            if(!root)
                return;
            TreeLinkNode* next_level = root;
            for(TreeLinkNode* node;;){
                node = next_level;
                next_level = node->left;
                if(!next_level)
                    break;
                TreeLinkNode* prev = NULL;
                while(node){
                    if(prev)
                        prev->next = node->left;
                    node->left->next = node->right;
                    prev = node->right;
                    node = node->next;
                }
            }
        }
    };
    

    117. Populating Next Right Pointers in Each Node II

    • 上一题的超集
    /**
     * Definition for binary tree with next pointer.
     * struct TreeLinkNode {
     *  int val;
     *  TreeLinkNode *left, *right, *next;
     *  TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void connect(TreeLinkNode *root) {
            TreeLinkNode *next_level = root;
            while(next_level){
                auto node = next_level;
                next_level = NULL;
                TreeLinkNode *prev = NULL;
                while(node){
                    if(node->left){
                        if(prev)
                            prev->next = node->left;
                        if(!next_level)
                            next_level = node->left;
                        prev = node->left;
                    }
                    if(node->right){
                        if(prev)
                            prev->next = node->right;
                        if(!next_level)
                            next_level = node->right;
                        prev = node->right;
                    }
                    node = node->next;
                }
            }
        }
    };
    

    118. Pascal's Triangle

    class Solution {
    public:
        vector<vector<int>> generate(int numRows) {
            vector<vector<int>> result;
            if(numRows==0)
                return result;
            result.push_back({1});
            for(int i=1;i<numRows;i++){
                auto& last = result.back();
                vector<int> row(i+1);
                row[0] = 1;
                for(int j=0; j<i; j++)
                    row[j+1] = last[j] + last[j+1];
                row[i] = 1;
                result.push_back(row);
            }
            return result;
        }
    };
    

    119. Pascal's Triangle II

    class Solution {
    public:
        vector<int> getRow(int rowIndex) {
            vector<int> row(rowIndex+1, 0);
            row[0] = 1;
            for(int i=0; i<rowIndex; i++)
                for(int j=i+1;j>0;j--)
                    row[j] += row[j-1];
            return row;
        }
    };
    

    120. Triangle

    • 动态规划
    class Solution {
    public:
        int minimumTotal(vector<vector<int>>& triangle) {
            vector<int> d = triangle.back();
            for(int i=triangle.size()-2; i>=0; i--){
                for(int j=0; j<i+1; j++){
                    d[j] = triangle[i][j] + min(d[j],d[j+1]);
                }
            }
            return d[0];
        }
    };
    

    121. Best Time to Buy and Sell Stock

    • 一次买,一次卖
      • 先买后卖,低买高卖
      • 遍历序列,记录当前的最小值
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()<=1)
                return 0;
            int lowest = prices[0], profit = 0;
            for(int x: prices){
                lowest = min(lowest, x);
                profit = max(x-lowest, profit);
            }
            return profit;
        }
    };
    
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            if(prices.size()<=1)
                return 0;
            int lowest = INT_MAX, profit = 0;
            for(int x: prices){
                lowest = min(lowest, x);
                profit = max(x-lowest, profit);
            }
            return profit;
        }
    };
    

    122. Best Time to Buy and Sell Stock II

    • 要求买入前已经卖出
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int profit = 0;
            for(int i=1; i<prices.size(); i++)
                profit += max(prices[i]-prices[i-1], 0);
            return profit;
        }
    };
    

    123. Best Time to Buy and Sell Stock III

    • 最多两次交易
    • 前后扫两趟,分治
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int n = prices.size();
            if(n<=1)
                return 0;
            vector<int> profit1(n, 0);
            vector<int> profit2(n, 0);
            int lowest = prices[0];
            for(int i=1; i<n; i++){
                lowest = min(lowest, prices[i]);
                profit1[i] = max(prices[i]-lowest, profit1[i-1]);
            }
            cout<<profit1[n-1]<<lowest<<endl;
            int highest = prices[n-1];
            for(int i=n-2; i>=0; i--){
                highest = max(highest, prices[i]);
                profit2[i] = max(highest-prices[i], profit2[i+1]);
            }
            cout<<profit2[0]<<highest<<endl;
            int profit = INT_MIN;
            for(int i=0; i<n; i++){
                profit = max(profit, profit1[i]+profit2[i]);
            }
            return profit;
        }
    };
    

    124. Binary Tree Maximum Path Sum

    • 加正数会变大
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        int ans = INT_MIN;
        int f(TreeNode* node){
            if(node){
                int val = node->val;
                int left = max(f(node->left), 0);
                int right = max(f(node->right), 0);
                ans = max(ans, left+right+val);
                return max(left,right)+val;
            }else{
                return 0;
            }
        }
    public:
        int maxPathSum(TreeNode* root) {
            f(root);
            return ans;
        }
    };
    

    125. Valid Palindrome

    class Solution {
    public:
        bool isPalindrome(string s) {
            if(s.empty())
                return true;
            for(int i=0, j=s.size()-1;;i++,j--){
                while(!isalnum(s[i]))
                    i++;
                while(!isalnum(s[j]))
                    j--;
                if(i>=j)
                    break;
                if(toupper(s[i])!=toupper(s[j]))
                    return false;                
            }
            return true;
        }
    };
    

    126. Word Ladder II

    class Solution {
        template<class Callback>
        inline void transform(string word,Callback callback){
            for(int i=0; i<word.size(); i++){
                char c = word[i];
                for(char j='a';j<='z';j++){
                    if(j!=c){
                        word[i] = j;
                        callback(word);
                    }
                }
                word[i] = c;
            }        
        }
    public:
        vector<vector<string>> findLadders(string beginWord, string endWord, unordered_set<string> &wordList) {
            unordered_map<string,int> dist;
            unordered_map<string,vector<string>> path;
            queue<string> q;
            q.push(beginWord);
            dist[beginWord] = 1;
            while(!q.empty()){
                auto x = q.front();
                q.pop();
                cout<<x<<endl;
                if(x==endWord)
                    break;
                transform(x, [&](const string& word){
                    if(wordList.count(word)){
                        if(dist[word]==0){
                            dist[word] = dist[x]+1;
                            q.push(word);
                        }
                        if(dist[word]==dist[x]+1)
                            path[word].push_back(x);
                    }
                });
            }
            vector<vector<string>> result;
            vector<string> item;
            function<void(const string&)> buildPath = [&](const string& node){
                if(node==beginWord){
                    auto item2 = item;
                    item2.push_back(node);
                    reverse(begin(item2),end(item2));
                    result.push_back(item2);
                    return;
                }
                item.push_back(node);
                for(auto& s:path[node])
                    buildPath(s);
                item.pop_back();
            };
            buildPath(endWord);
            return result;        
        }
    };
    

    127. Word Ladder

    • 图论,广度优先搜索
      • 用队列实现
    • 这题给个测试用例单词很短,但是单词数量很多
      • 比如说有个 5 的字符长度(5*25=125个变换),2370 个单词的
      • 这种情况下用字符串两两比较会超时
    class Solution {
        bool adjacent(const string& s1, const string& s2){
            if(s1.size()!=s2.size())
                return false;
            int count = 0;
            for(int i=0; i<s1.size() && count<2; i++){
                if(s1[i]!=s2[i])
                    count++;
            }
            return count==1;
        }
    public:
        int ladderLength(string beginWord, string endWord, unordered_set<string>& wordList) {
            unordered_map<string,int> dist;
            queue<string> q;
            q.push(beginWord);
            dist[beginWord] = 1;
            while(!q.empty()){
                auto x = q.front();
                q.pop();
                if(x==endWord)
                    break;
                string o = x;
                for(int i=0; i<x.size(); i++){
                    char c = x[i];
                    for(char j='a';j<='z';j++){
                        if(j!=c){
                            x[i] = j;
                            if(wordList.count(x) && !dist[x]){
                                q.push(x);
                                dist[x] = dist[o]+1;
                            }
                        }
                    }
                    x[i] = c;
                }
                // for(auto v: wordList){
                //     if(!dist[v] && adjacent(x,v)){
                //         q.push(v);
                //         dist[v] = dist[x]+1;
                //     }
                // }
            }
            return dist[endWord];
        }
    };
    

    128. Longest Consecutive Sequence

    • 要求 O(N)
    class Solution {
        unordered_map<int,int> h;
        int ds_find(int x){
            if(h[x]!=x)
                h[x] = ds_find(h[x]);
            return h[x];
        }
        void ds_union(int x, int y){
            h[ds_find(x)] = ds_find(y);
        }
    public:
        int longestConsecutive(vector<int>& nums) {
            for(int x: nums)
                h[x] = x;
            for(int x: nums){
                if(h.count(x+1))
                    ds_union(x, x+1);
                if(h.count(x-1))
                    ds_union(x, x-1);
            }
            unordered_map<int,int> a;
            for(auto p: h)
                a[ds_find(p.second)]++;
            int ans = 0;
            for(auto p: a)
                ans = max(ans, p.second);
            return ans;
        }
    };
    

    129. Sum Root to Leaf Numbers

    • 二叉树
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int sumNumbers(TreeNode* root) {
            function<int(TreeNode*,int)> f = [&](TreeNode* node,int num){
                if(!node)
                    return 0;
                num = num*10 + node->val;
                if(!node->left && !node->right)
                    return num;
                return f(node->left, num)+f(node->right, num);
            };
            return f(root, 0);
        }
    };
    

    130. Surrounded Regions

    • 递归会爆栈,
      • LeetCode 显示 RunTime Error
    class Solution {
    public:
        void solve(vector<vector<char>>& board) {
            int m = board.size();
            if(m==0)
                return;
            int n = board[0].size();
            function<void(int,int)> f = [&](int x, int y){
                if(board[y][x]=='O'){
                    board[y][x] = 'T';
                    if(y+1 < m-1)
                        f(x, y+1);
                    if(y-1 > 0)
                        f(x, y-1);
                    if(x+1 < n-1)
                        f(x+1, y);
                    if(x-1 > 0)
                        f(x-1, y);
                }
            };
            for(int i=0; i<n; i++){
                f(i, 0);
                f(i, m-1);
            }
            for(int j=0; j<m; j++){
                f(0, j);
                f(n-1, j);
            }
            for(auto& xs: board)
                for(auto& x: xs)
                    if(x=='O')
                        x = 'X';
                    else if(x=='T')
                        x = 'O';
        }
    };
    

    131. Palindrome Partitioning

    Backtracking

    • 深度优先搜索
    • 动态规划
    class Solution {
        bool  isPalindrome(const string& s, int start, int last){
            while(start<last){
                if(s[start]!=s[last])
                    return false;
                start++, last--;
            }
            return true;
        }
    public:
        vector<vector<string>> partition(string s) {
            vector<vector<string>> result;
            //unordered_map<string,vector<string>> h;
            vector<string> path;
            function<void(int)> f = [&](int i){
                if(i==s.size()){
                    result.push_back(path);
                    return;
                }
                for(int j=i; j<s.size(); j++){
                    if(isPalindrome(s,i,j)){
                        path.push_back(s.substr(i,j-i+1));
                        f(j+1);
                        path.pop_back();
                    }
                }
            };
            f(0);
            return result;
        }
    };
    

    132. Palindrome Partitioning II

    • 求最小割数
    • 长度 n 最多 n-1 个割
    • 一个字串可以递归分解为一个回文子串和另一个字串
    class Solution {
    public:
        int minCut(string s) {
            int n = s.size();
            vector<int> c(n+1);
            vector<vector<bool>> d(n,vector<bool>(n));
            for(int i=0; i<=n; i++)
                c[i] = i - 1;
            for(int i=0; i<n; i++)
                for(int j=i; j>=0; j--)
                    if(s[j]==s[i] && (i-j<3 || d[j+1][i-1])){
                        d[j][i] = true;
                        c[i+1] = min(c[i+1], c[j]+1);
                    }
            return c[n];
        }
    };
    
    class Solution {
    public:
        int minCut(string s) {
            int n = s.size();
            vector<int> c(n+1);
            vector<vector<bool>> d(n,vector<bool>(n));
            for(int i=0; i<=n; i++)
                c[i] = i - 1;
            for(int i=0; i<n; i++)
                for(int j=0; j<=i; j++)
                    if(s[j]==s[i] && (i-j<3 || d[j+1][i-1])){
                        d[j][i] = true;
                        c[i+1] = min(c[i+1], c[j]+1);
                    }
            return c[n];
        }
    };
    

    133. Clone Graph

    • 哈希表
    • 递归
    /**
     * Definition for undirected graph.
     * struct UndirectedGraphNode {
     *     int label;
     *     vector<UndirectedGraphNode *> neighbors;
     *     UndirectedGraphNode(int x) : label(x) {};
     * };
     */
    class Solution {
    public:
        UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
            unordered_map<UndirectedGraphNode*,UndirectedGraphNode*> h;
            function<UndirectedGraphNode*(UndirectedGraphNode*)> f = [&](UndirectedGraphNode* node){
                auto it = h.find(node);
                if(it!=h.end())
                    return it->second;
                auto new_node = new UndirectedGraphNode(node->label);
                h[node] = new_node;
                for(auto e: node->neighbors)
                    new_node->neighbors.push_back(f(e));
                return new_node;
            };
            return node ? f(node) : nullptr;
        }
    };
    

    134. Gas Station

    • 一趟
    • 有两个目标
      1. 判断是否能完成
      2. 寻找起点
    class Solution {
    public:
        int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
            int a = 0, d = 0;
            int start = 0;
            for(int i=0; i<gas.size(); i++){
                d += gas[i] - cost[i];
                if(d<0){
                    a += d;
                    d = 0;
                    start = i+1;
                }
            }
            return a+d>=0 ? start : -1;
        }
    };
    

    135. Candy

    • 记录变化量
    int candy(int* ratings, int ratingsSize) {
        int a, *d = (int*)calloc(ratingsSize,sizeof(int));
        a = 1;
        for(int i=1; i<ratingsSize; i++){
            if(ratings[i] > ratings[i-1]){
                if(d[i]<a)
                    d[i] = a;
                a++;
            }else{
                a = 1; 
            }
        }
        a = 1;
        for(int i=ratingsSize-2; i>=0; i--){
            if(ratings[i] > ratings[i+1]){
                if(d[i]<a)
                    d[i] = a;
                a++;
            }else{
                a = 1;
            }
        }
        int sum = ratingsSize;
        for(int i=0; i<ratingsSize; i++){
            sum += d[i];
        }
        return sum;
    }
    

    136. Single Number

    • 整数的位运算
    • 异或运算,和零异或为自己,和自己异或为 0
    int singleNumber(int* nums, int numsSize) {
        int x = 0;
        for(int i=0; i<numsSize; i++)
            x ^= nums[i];
        return x;
    }
    

    137. Single Number II

    • 二进制位加法
      • 异或运算得到值,与运算得到进位
    • 本题得到 0b11 时再取模
    class Solution {
    public:
        int singleNumber(vector<int>& nums) {
            int a=0, b=0;
            for(int x: nums){
                b ^= a&x;
                a ^= x;
                int c = ~(a&b);
                a &= c;
                b &= c;
            }
            return a;
        }
    };
    

    138. Copy List with Random Pointer

    • 图的复制
    /**
     * Definition for singly-linked list with a random pointer.
     * struct RandomListNode {
     *     int label;
     *     struct RandomListNode *next;
     *     struct RandomListNode *random;
     * };
     */
    struct RandomListNode *copyRandomList(struct RandomListNode *head) {
        typedef struct RandomListNode Node;
        if(!head)
            return NULL;
        for(Node* node=head; node;){
            Node* copy = (Node*)malloc(sizeof(Node));
            *copy = *node;
            node->next = copy;
            node = copy->next;
        }
        for(Node* node=head; node;){
            Node* copy = node->next;
            if(copy->random)
                copy->random = copy->random->next;
            node = copy->next;
        }
        Node *head2 = head->next;
        for(Node *node = head; node;){
            Node *node2 = node->next;
            Node *next = node2->next;
            node->next = next;
            node2->next = next ? next->next : NULL;
            node = next;
        }
        return head2;
    }
    
    /**
     * Definition for singly-linked list with a random pointer.
     * struct RandomListNode {
     *     int label;
     *     RandomListNode *next, *random;
     *     RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
     * };
     */
    class Solution {
    public:
        RandomListNode *copyRandomList(RandomListNode *head) {
            unordered_map<RandomListNode*,RandomListNode*> h;
            auto get = [&](RandomListNode* node)->RandomListNode*{
                if(!node)
                    return NULL;
                auto it = h.find(node);
                if(it!=h.end())
                    return it->second;
                else{
                    return h[node] = new RandomListNode(node->label);
                }
            };
            for(auto p=head; p; p=p->next){
                auto node_clone = get(p);
                node_clone->random = get(p->random);
                node_clone->next = get(p->next);
            }
            return h[head];
        }
    };
    

    139. Word Break

    • 动态规划
    • 分词/递归
    class Solution {
    public:
        bool wordBreak(string s, vector<string>& wordDict) {
            unordered_set<string> dict;
            for(auto& x: wordDict)
                dict.insert(x);
            vector<bool> d(s.size()+1, false);
            d[0] = true;
            for(int i=1;i<=s.size();i++)
                for(int j=i-1;j>=0;j--)
                    if(d[j] && dict.count(s.substr(j, i-j))){
                        d[i] = true;
                        break;
                    }
            return d.back();
        }
    };
    
    class Solution {
    public:
        bool wordBreak(string s, vector<string>& wordDict) {
            unordered_set<string> dict;
            int len = 0;
            for(auto& x: wordDict){
                dict.insert(x);
                len = max(len,(int)x.size());
            }
            unordered_map<int,bool> m;
            function<bool(int)> f = [&](int i){
                if(i==s.size())
                    return true;
                auto it = m.find(i);
                if(it!=m.end())
                    return it->second;
                for(int j=i+1; j<=s.size() && j-i<=len; j++)
                    if(dict.count(s.substr(i,j-i)) && f(j))
                        return m[i] = true;
                return m[i] = false;
            };
            return f(0);
        }
    };
    

    140. Word Break II

    class Solution {
    public:
        vector<string> wordBreak(string s, vector<string>& wordDict) {
            unordered_set<string> dict;
            for(auto& x: wordDict)
                dict.insert(x);
            int n = s.size();
            vector<vector<int>> edge(n+1,vector<int>());
            edge[0].push_back(0);
            for(int i=1; i<=n; i++)
                for(int j=i-1; j>=0; j--)
                    if(edge[j].size() && dict.count(s.substr(j, i-j))){
                        edge[i].push_back(j);
                        printf("(%d->%d)\n",j,i);
                    }
            vector<string> result;
            vector<string> path;
            function<void(int)> f = [&](int i){
                if(i==0){
                    string item;
                    for(int j=path.size()-1; j>=0; j--){
                        item += path[j];
                        item += ' ';
                    }
                    item.pop_back();
                    result.push_back(item);
                    return;
                }
                for(auto j: edge[i]){
                    path.push_back(s.substr(j, i-j));
                    f(j);
                    path.pop_back();
                }
            };
            f(n);
            return result;
        }
    };
    

    141. Linked List Cycle

    • 链表,双指针
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        bool hasCycle(ListNode *head) {
            auto fast = head, slow = head;
            while(fast && fast->next){
                fast = fast->next->next;
                slow = slow->next;
                if(fast==slow)
                    return true;
            }
            return false;
        }
    };
    

    142. Linked List Cycle II

    List

    • 链表
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode *detectCycle(ListNode *head) {
            auto fast = head, slow = head;
            while(fast && fast->next){
                fast = fast->next->next;
                slow = slow->next;
                if(fast==slow){
                    auto node = head;
                    while(node!=slow){
                        slow = slow->next;
                        node = node->next;
                    }
                    return node;
                }
            }
            return NULL;        
        }
    };
    

    143. Reorder List

    • 链表
    • 原地逆置+链表合并+快慢双指针
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
        ListNode* nreverse(ListNode* head){
            ListNode* prev = NULL;
            while(head){
                auto next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            return prev;
        }
        void merge(ListNode* head1,ListNode* head2){
            while(head2){
                auto next1 = head1->next;
                auto next2 = head2->next;
                head1->next = head2;
                head2->next = next1;
                head1 = next1;
                head2 = next2;
            }
        }
        ListNode* cut(ListNode* head){
            auto fast = head, slow = head;
            while(fast && fast->next){
                fast = fast->next->next;
                slow = slow->next;
            }
            auto head2 = slow->next;
            slow->next = NULL;
            return head2;
        }
    public:
        void reorderList(ListNode* head) {
            if(head)
                merge(head,nreverse(cut(head)));
        }
    };
    

    144. Binary Tree Preorder Traversal

    • 重点问题!
    • 二叉树先序遍历
      • NLR,先访问根节点
    • 递归,非递归实现
      • 出栈顺序
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> preorderTraversal(TreeNode* root) {
            vector<int> result;
            stack<TreeNode*> s;
            if(root)
                s.push(root);
            while(!s.empty()){
                TreeNode* node = s.top();
                s.pop();
                result.push_back(node->val);
                if(node->right)
                    s.push(node->right);
                if(node->left)
                    s.push(node->left);
            }
            return result;
        }
    };
    

    145. Binary Tree Postorder Traversal

    Tree

    • 二叉树后序遍历的迭代实现
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> postorderTraversal(TreeNode* root) {
            vector<int> result;
            stack<TreeNode*> s;
            TreeNode *p = root;
            TreeNode *q = NULL;
            for(;;){
                if(p){
                    s.push(p);
                    p = p->left;
                }else if(!s.empty()){
                    p = s.top();
                    if(q==p->right || !p->right){
                        result.push_back(p->val);
                        q = p;
                        s.pop();
                        p = NULL;
                    }else{
                        p = p->right;
                    }
                }else{
                    break;
                }
            }
            return result;
        }
    };
    

    146. LRU Cache

    • 需要在 O(1) 时间找到链表中的节点并移动到头部
      • 利用双向链表和哈希表
      • c++ 的 splice 用来把另一个链表中的元素插入该位置前
    class LRUCache{
        int capacity;
        unordered_map<int,list<pair<int,int>>::iterator> h;
        list<pair<int,int>> l;
    public:
        LRUCache(int capacity) {
            this->capacity = capacity;
        }
        
        int get(int key) {
            auto it = h.find(key);
            if(it==h.end())
                return -1;
            l.splice(l.begin(), l, it->second);
            return it->second->second;
        }
        
        void set(int key, int value) {
            auto it = h.find(key);
            if(it!=h.end()){
                it->second->second = value;
                l.splice(l.begin(), l, it->second);
            }else{
                if(l.size()==capacity){
                    h.erase(l.back().first);
                    l.pop_back();
                }
                l.push_front(make_pair(key, value));
                h[key] = l.begin(); 
            }
        }
    };
    

    147. Insertion Sort List

    • 数组一般从后往前插
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* insertionSortList(ListNode* head) {
            ListNode* list = NULL;
            auto node = head;
            while(node){
                auto next = node->next;
                auto p = &list;
                while(*p && node->val > (*p)->val)
                    p = &(*p)->next;
                node->next = *p;
                *p = node;
                node = next;
            }
            return list;
        }
    };
    

    148. Sort List

    • 链表
    • 归并排序
    • 结合前面的题目
      • 21. Merge Two Sorted Lists,直接搬过来递归使用
      • 143. Reorder List,那题有两个节点的话不用断开,这题要。
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
        ListNode* cut(ListNode* head){
            auto fast = head, slow = head;
            while(fast && fast->next && fast->next->next){
                fast = fast->next->next;
                slow = slow->next;
            }
            auto head2 = slow->next;
            slow->next = NULL;
            return head2;
        }
        ListNode* nmerge(ListNode* head1,ListNode* head2){
            ListNode* head = NULL;
            ListNode** append = &head; 
            for(;;){
                if(!head1){
                    *append = head2;
                    break;
                }
                if(!head2){
                    *append = head1;
                    break;
                }
                if(head1->val < head2->val){
                    *append = head1;
                    head1 = head1->next;
                }else{
                    *append = head2;
                    head2 = head2->next;
                }
                append = &(*append)->next;
            }
            return head;
        }
    public:
        ListNode* sortList(ListNode* head) {
            if(!head || !head->next)
                return head;
            auto head2 = cut(head);
            return nmerge(sortList(head),sortList(head2));
        }
    };
    

    149. Max Points on a Line

    • 注意出现重合的点的情况
      • [[1,1],[1,1],[1,1]]
    • 该题的坐标是整数
    /**
     * Definition for a point.
     * struct Point {
     *     int x;
     *     int y;
     *     Point() : x(0), y(0) {}
     *     Point(int a, int b) : x(a), y(b) {}
     * };
     */
    class Solution {
    public:
        int maxPoints(vector<Point>& points) {
            int n = points.size();
            if(n<=2)
                return points.size();
            int m = 2;
            for(int i=0; i<n; i++){
                int start = 2;
                for(int j=i+1; j<n-1; j++){
                    int dx = points[j].x-points[i].x;
                    int dy = points[j].y-points[i].y;
                    if(dx==0 && dy==0){
                        start++;
                        continue;
                    }
                    int bdx = dx*points[i].y - dy*points[i].x; 
                    int count = start;
                    for(int k=j+1; k<n; k++){
                        if(dx==0){
                            if(points[k].x == points[j].x)
                                    count++;
                        }else{
                            if(dx*points[k].y==dy*points[k].x+bdx)
                                    count++;
                        }
                    }
                    m = max(m, count);
                }
                m = max(m, start);
            }
            return m;
        }
    };
    

    150. Evaluate Reverse Polish Notation

    • Stack
    int evalRPN(char** tokens, int tokensSize) {
        int size = 3;
        int* stack = (int*)malloc(sizeof(int)*size);
        int *p = stack;
        for(int i=0; i<tokensSize; i++){
            char *token = tokens[i];
            if(token[0] && !token[1]){
                switch(token[0]){
                    case '+':
                        p[-2] += p[-1];
                        p--;
                        continue;
                    case '-':
                        p[-2] -= p[-1];
                        p--;
                        continue;
                    case '*':
                        p[-2] *= p[-1];
                        p--;
                        continue;
                    case '/':
                        p[-2] /= p[-1];
                        p--;
                        continue;
                }
            }
            if(p-stack==size){
                stack = realloc(stack,sizeof(int)*(size*2));
                p = stack+size;
                size *= 2;
            }
            *p++ = atoi(token);
        }
        int ans = p[-1];
        free(stack);
        return ans;
    }
    

    151. Reverse Words in a String

    Application

    • 逆置
    • 原地,一趟。
    class Solution {
        void reverse(string& s, int i, int j){
            while(i<j)
                swap(s[i++],s[j--]);
        }
        void compact(string& s){
            int k = 0;
            for(int i=0; i<s.size(); i++)
                if(s[i]!=' '){
                    if(k!=0)
                        s[k++] = ' ';
                    int j = i;
                    while(j<s.size() && s[j]!=' ')
                        s[k++] = s[j++];
                    i = j;
                }
            s.resize(k);
        }
    public:
        void reverseWords(string &s) {
            compact(s);
            ::reverse(s.begin(), s.end());
            int start = 0;
            while(start<s.size() && s[start]==' ')
                start++;
            for(int i=0; i<s.size(); i++){
                if(s[i]==' '){
                    reverse(s, start, i-1);
                    start = i+1;
                }
            }
            reverse(s, start, s.size()-1);
        }
    };
    

    152. Maximum Product Subarray

    • 积最大
    • 正负
    class Solution {
    public:
        int maxProduct(vector<int>& nums) {
            int m = INT_MIN;
            int a = 1, b = 1;
            for(int x: nums){
                int c = max(x, max(a*x, b*x));
                b = min(x, min(a*x, b*x));
                m = max(m, c);
                a = c;
            }
            return m;
        }
    };
    

    153. Find Minimum in Rotated Sorted Array

    这个解答有问题。。。

    class Solution {
    public:
        int findMin(vector<int>& nums) {
            int a = 0, b = nums.size();
            while(a<b){
                int c = (a+b-1)/2;
                if(nums[a]<=nums[b-1]){
                    return nums[a];
                }else if(nums[c]>nums[b-1]){
                    a = c + 1;
                }else{
                    b = c + 1;
                }
            }
            return INT_MIN;
        }
    };
    

    154. Find Minimum in Rotated Sorted Array II

    • 有重复元素
    class Solution {
    public:
        int findMin(vector<int>& nums) {
            int a = 0, b = nums.size()-1;
            while(a<b){
                int c = (a+b)/2;
                if(nums[a]<nums[b])
                    break;
                else if(nums[c]>nums[b])
                    a = c + 1;
                else if(nums[a]>nums[c])
                    b = c;
                else
                    a++;
            }
            return nums[a];
        }
    };
     
    
    class Solution {
    public:
        int findMin(vector<int>& nums) {
            int a = 0, b = nums.size();
            while(b-a>1){
                int c = (a+b-1)/2;
                if(nums[a]<nums[b-1])
                    break;
                else if(nums[c]>nums[b-1])
                    a = c + 1;
                else if(nums[a]>nums[c])
                    b = c + 1;
                else
                    a++;
            }
            return nums[a];
        }
    };
    

    155. Min Stack

    • 栈,先进先出
    • 用另一个栈记录最小元素
    • STL 中空栈取元素是未定义行为
    class MinStack {
        stack<int> _stack;
        stack<int> _stack_min;
    public:
        /** initialize your data structure here. */
        MinStack() {
            
        }
        
        void push(int x) {
            _stack.push(x);
            if(_stack_min.empty() || x<=_stack_min.top())
                _stack_min.push(x);
        }
        
        void pop() {
            int x = _stack.top();
            _stack.pop();
            if(!_stack_min.empty() && x==_stack_min.top())
                _stack_min.pop();
        }
        
        int top() {
            return _stack.top();
        }
        
        int getMin() {
            return _stack_min.top();
        }
    };
    
    /**
     * Your MinStack object will be instantiated and called as such:
     * MinStack obj = new MinStack();
     * obj.push(x);
     * obj.pop();
     * int param_3 = obj.top();
     * int param_4 = obj.getMin();
     */
    

    160. Intersection of Two Linked Lists

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
        int list_length(ListNode* head){
            int n=1;
            while(head){
                n++;
                head = head->next;
            }
            return n;
        }
    public:
        ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            int lenA = list_length(headA);
            int lenB = list_length(headB);
            if(lenA>lenB){
                for(int i=lenA-lenB; i>0; i--)
                    headA = headA->next;
            }else{
                for(int i=lenB-lenA; i>0; i--)
                    headB = headB->next;
            }
            while(headA!=headB){
                headA = headA->next;
                headB = headB->next;
            }
            return headA;
        }
    };
    

    162. Find Peak Element

    • 二分查找
    • 找极大值
    • 越界为负无穷
    class Solution {
    public:
        int findPeakElement(vector<int>& nums) {
            auto less = [&](int i, int j){
                if(i==-1 || i==nums.size())
                    return true;
                if(j==-1 || j==nums.size())
                    return false;
                return nums[i] < nums[j];  
            };
            int a = 0, b = nums.size();
            while(a<b){
                int c = (a+b)/2;
                if(less(c-1,c) && less(c, c+1))
                    a = c + 1;
                else if(less(c+1, c) && less(c, c-1))
                    b = c;
                else if(less(c+1, c) && less(c-1, c))
                    return c;
                else
                    b = c;
            }
            return -1;
        }
    };
    

    164. Maximum Gap

    Sort

    • 先排序 O(N),后查找 O(N)
    //http://zh.wikipedia.org/zh-cn/%E5%9F%BA%E6%95%B0%E6%8E%92%E5%BA%8F
    void radixsort(int data[], int n){
        int m = 0;
        for(int i=0;i<n;i++)
            if(data[i]>m)
                m = data[i];
        int *tmp = (int*)malloc(sizeof(int)*n);
        memset(tmp, 0, sizeof(int)*n);
        int count[10] = {0};
        for(unsigned radix=1;radix<=m;radix*=10){
            for(int i=0;i<10;i++)
                count[i] = 0;
            for(int i=0; i<n; i++)
                count[(data[i]/radix)%10]++;
            for(int i=1; i<10; i++)
                count[i] += count[i-1];
            for(int i=n-1; i>=0; i--)
                tmp[--count[(data[i]/radix)%10]] = data[i];
            for(int i=0; i<n; i++)
                data[i] = tmp[i];
        }
        free(tmp);
    }
    int maximumGap(int num[], int n) {
        if(n<2)
            return 0;
        radixsort(num,n);
        int pred = num[0];
        int max = 0;
        for(int i=1;i<n;i++){
            int curr = num[i];
            int delta = curr>pred ? curr-pred : pred-curr;
            if(delta>max)
                max = delta;
            pred = curr;
        }
        return max;
    }
    

    165. Compare Version Numbers

    int compareVersion(char* version1, char* version2) {
        while(*version1 || *version2){
            int a = strtol(version1,&version1,10);
            int b = strtol(version2,&version2,10);
            if(*version1=='.')version1++;
            if(*version2=='.')version2++;
            if(a<b)return -1;
            if(a>b)return 1;
        }
        return 0;
    }
    

    166. Fraction to Recurring Decimal

    class Solution {
        void append(string& s, unsigned n){
            stringstream ss;
            ss << n;
            s += ss.str();         
        }
    public:
        string fractionToDecimal(int numerator, int denominator) {
            string s;
            if(numerator==0)
                return "0";
            if((numerator^denominator)&(1<<31))
                 s += "-";
            long long a = llabs((long long)numerator), b = llabs((long long)denominator);
            append(s, a/b); 
            a %= b;
            if(a!=0){
                s.push_back('.');
                unordered_map<unsigned,int> h;
                for(int i=s.size(); a; i++){
                    if(h.count(a)){
                        s.insert(h[a], "(");
                        s.push_back(')');
                        break;
                    }
                    h[a] = i;
                    a *= 10;
                    append(s, a/b);
                    a %= b;
                }
            }
            return s;
        }
    };
    

    167. Two Sum II - Input array is sorted

    • 这题没意思
    class Solution {
    public:
        vector<int> twoSum(vector<int>& numbers, int target) {
            int i = 0, j = numbers.size()-1;
            while(i<j){
                int s = numbers[i] + numbers[j];
                if(s==target)
                    return {i+1, j+1};
                else if(s<target)
                    i++;
                else
                    j--;
            }
            return {0,0};
        }
    };
    

    168. Excel Sheet Column Title

    class Solution {
    public:
        string convertToTitle(int n) {
            string s;
            while(n){
                n--;
                s += 'A'+ n%26;
                n /= 26;
            }
            reverse(s.begin(), s.end());
            return s;
        }
    };
    

    169. Majority Element

    • 数组老题,题干有若干假设
    int majorityElement(int* nums, int numsSize) {
        int x = nums[0];
        int count = 1;
        for(int i=1; i<numsSize; i++){
            if(nums[i]==x){
                count++;
            }else{
                count--;
                if(count==0){
                    x = nums[i];
                    count=1;
                }
            }
        }
        return x;
    }
    

    171. Excel Sheet Column Number

    int titleToNumber(char* s) {
        int n = 0;
        for(;*s;s++)
            n = n*26+*s-'A'+1;
        return n;
    }
    

    172. Factorial Trailing Zeroes

    索引:整数

    • 求区间上因子5的个数
    int trailingZeroes(int n) {
        int a = 0;
        while(n>=5){
            n /= 5;
            a += n;
        }
        return a;
    }
    

    173. Binary Search Tree Iterator

    • 二叉树的中序遍历
    • 写成外迭代器的形式
    /**
     * Definition for binary tree
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class BSTIterator {
        stack<TreeNode*> s;
    public:
        BSTIterator(TreeNode *root) {
            auto p = root;
            while(p){
                s.push(p);
                p = p->left;
            }
        }
    
        /** @return whether we have a next smallest number */
        bool hasNext() {
            return !s.empty();
        }
    
        /** @return the next smallest number */
        int next() {
            auto p = s.top();
            s.pop();
            int val = p->val;
            p = p->right;
            while(p){
                s.push(p);
                p = p->left;
            }
            return val;
        }
    };
    
    /**
     * Your BSTIterator will be called like this:
     * BSTIterator i = BSTIterator(root);
     * while (i.hasNext()) cout << i.next();
     */
    

    174. Dungeon Game

    DP

    • 深搜,符合DP的两个条件
    • 路径上一直大于零。
    class Solution {
    public:
        int calculateMinimumHP(vector<vector<int>>& dungeon) {
            int m = dungeon.size();
            int n = dungeon[0].size();
            int d[n];
            d[n-1] = max(-dungeon[m-1][n-1], 0);
            for(int j=n-2;j>=0;j--)
                d[j] = max(d[j+1]-dungeon[m-1][j], 0);
            for(int i=m-2;i>=0;i--){
                d[n-1] = max(d[n-1]-dungeon[i][n-1], 0);
                for(int j=n-2;j>=0;j--){
                    int cost = dungeon[i][j];
                    d[j] = min(d[j]-cost, d[j+1]-cost);
                    d[j] = max(d[j], 0);
                }
            }
            return d[0]+1;
        }
    };
    

    179. Largest Number

    class Solution {
    public:
        string largestNumber(vector<int>& nums) {
            vector<string> xs;
            for(int x: nums){
                stringstream ss;
                ss << x;
                xs.push_back(ss.str());
            }
            sort(begin(xs), end(xs),[](const string& a, const string& b){
                return a+b > b+a;
            });
            if(xs.size()==0 || xs[0]=="0")
                return "0";
            stringstream ss;
            for(auto& x: xs)
                ss << x;
            return ss.str();
        }
    };
    

    187. Repeated DNA Sequences

    • 查找
    class Solution {
    public:
        vector<string> findRepeatedDnaSequences(string s) {
            vector<string> result;
            unordered_map<char, int> m = {{'A',0},{'C',1},{'G',2},{'T',3}};
            unordered_map<int, int> h;
            int key = 0;
            for(int i=0; i<9; i++)
                key = (key<<2) | m[s[i]];
            for(int i=9; i<s.size(); i++){
                key = ((key<<2) | m[s[i]]) & ((1<<20) - 1);
                if(++h[key]==2)
                    result.push_back(s.substr(i-9, 10));
            }
            return result;
        }
    };
    

    188. Best Time to Buy and Sell Stock IV

    • 买卖交替
    • k 很大的情况
    • k==2 的情况
    class Solution {
    public:
        int maxProfit(int k, vector<int>& prices) {
            if(k>=prices.size()/2){
                int ans = 0;
                for(int i=1; i<prices.size(); i++){
                    int d = prices[i] - prices[i-1];
                    ans += max(d, 0);
                }
                return ans;
            }        
            vector<int> l(k+1);
            vector<int> g(k+1);
            for(int i=1; i<prices.size();i++){
                int d = prices[i] - prices[i-1];
                for(int j=k; j>=1; j--){
                    l[j] = max(g[j-1]+max(d,0), l[j]+d);
                    g[j] = max(g[j], l[j]);
                }
            }
            return g[k];
        }
    };
    

    189. Rotate Array

    Array

    • 数组问题
    • 三次逆置
    void reverse(int* nums, int i, int j){
        for(; i<j; i++,j--){
            int t = nums[i];
            nums[i] = nums[j];
            nums[j] = t;
        }
    }
    void rotate(int* nums, int numsSize, int k) {
        k %= numsSize;
        if(k==0)
            return;
        reverse(nums,0,numsSize-k-1);
        reverse(nums,numsSize-k,numsSize-1);
        reverse(nums,0,numsSize-1);
    }
    

    190. Reverse Bits

    uint32_t reverseBits(uint32_t n) {
        int a = 0;
        for(int i=0; i<32; i++){
            a <<= 1;
            a |= n&1;
            n >>= 1;
        }
        return a;
    }
    

    191. Number of 1 Bits

    • 整数位运算经典题
    • 一次迭代去掉一个最低位的1
      • 发生二进制减法借位
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n){
            count++;
            n &= n-1;
        }
        return count;
    }
    

    198. House Robber

    DP

    • 应用题,动态规划
    class Solution {
    public:
        int rob(vector<int>& nums) {
            int n = nums.size();
            if(n==0)
                return 0;
            if(n==1)
                return nums[0];
            vector<int> d(n);
            d[0] = nums[0];
            d[1] = max(d[0], nums[1]);
            for(int i=2; i<nums.size(); i++)
                d[i] = max(d[i-1], d[i-2]+nums[i]);
            return d[n-1];
        }
    };
    

    199. Binary Tree Right Side View

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        vector<int> rightSideView(TreeNode* root) {
            vector<int> result;
            queue<TreeNode*> q;
            if(root)
                q.push(root);
            while(!q.empty()){
                result.push_back(q.back()->val);
                int n = q.size();
                while(n--){
                    auto node = q.front();
                    q.pop();
                    if(node->left)
                        q.push(node->left);
                    if(node->right)
                        q.push(node->right);
                }
            }
            return result;
        }
    };
    

    200. Number of Islands

    Graph

    void fill(char **grid, int m, int n, int y, int x) {
        if(grid[y][x]=='1'){
            grid[y][x] = '0';
            if(y>0)
                fill(grid, m, n, y-1, x);
            if(y+1<m)
                fill(grid, m, n, y+1, x);
            if(x>0)
                fill(grid, m, n, y, x-1);
            if(x+1<n)
                fill(grid, m, n, y, x+1);
        }
    }
    int numIslands(char** grid, int gridRowSize, int gridColSize) {
        int count = 0;
        for(int y=0;y<gridRowSize;y++)
            for(int x=0;x<gridColSize;x++){
                if(grid[y][x]=='1'){
                    fill(grid, gridRowSize, gridColSize, y, x);
                    count++;
                }
            }
        return count;
    }
    

    201. Bitwise AND of Numbers Range

    Integer

    • 位运算的转化,覆盖区间上的数
    class Solution {
    public:
        int rangeBitwiseAnd(int m, int n) {
            unsigned b = -1;
            while((m&b)!=(n&b))
                b <<= 1;
            return m&b;
        }
    };
    

    202. Happy Number

    class Solution {
        int next(int x){
            int y = 0;
            while(x){
                y += (x%10)*(x%10);
                x /= 10;
            }
            return y;
        }
    public:
        bool isHappy(int n) {
            unordered_map<int,bool> h;
            while(n!=1){
                if(h.count(n))
                    return false;
                h[n] = true;
                n = next(n);
            }
            return true;
        }
    };
    

    203. Remove Linked List Elements

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* removeElements(ListNode* head, int val) {
            auto list = &head;
            while(*list){
                if((*list)->val==val)
                    *list = (*list)->next;
                else
                    list = &(*list)->next;
            }
            return head;
        }
    };
    

    204. Count Primes

    • 质数
    int countPrimes(int n) {
        int count = 0;
        bool h[n];
        memset(h,-1,sizeof(bool)*n);
        h[0] = h[1] = 0;
        for(int i=2; i<n; i++)
            if(h[i])
                for(int j=i<<1; j<n; j+=i)
                    h[j] = 0;
        for(int i=0; i<n; i++)
            if(h[i])
                count++;
        return count;
    }
    

    205. Isomorphic Strings

    bool isIsomorphic(char* s, char* t) {
        char h[128] = {0}, r[128] = {0};
        while(*s){
            if(h[*s] == 0 && r[*t]==0){
                h[*s] = *t;
                r[*t] = *s;
            }else if(h[*s]!=*t)
                return false;
            s++, t++;
        }
        return true;
    }
    

    206. Reverse Linked List

    • 链表经典问题
    • 原地逆置链表
    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode* prev = NULL;
            while(head){
                ListNode* next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            return prev;
        }
    };
    

    207. Course Schedule

    Graph

    • 有趣的题目
    • 有向图拓扑排序,判断是否有环
      • 用深度优先搜索实现
    class Solution {
    public:
        bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
            unordered_map<int,int> h;
            function<bool(int)> f = [&](int x){
                if(h[x]==1)
                    return true;
                if(h[x]==2)
                    return false;
                h[x] = 1;
                for(auto p: prerequisites)
                    if(p.first==x){
                        if(f(p.second))
                            return true;
                    }
                h[x] = 2;
                return false;
            };
            for(int i=0; i<numCourses; i++)
                if(f(i))
                    return false;
            return true;
        }
    };
    

    208. Implement Trie (Prefix Tree)

    • 字符串查找,前缀
    • 后面有个题目会用到这个数据结构
    class Trie {
        struct Node{
            Node* next[26];
            bool term;
            Node(){
                memset(this,0,sizeof(Node));
            }
        };
        Node* root;
    public:
        /** Initialize your data structure here. */
        Trie() {
            root = new Node();
        }
        
        /** Inserts a word into the trie. */
        void insert(string word) {
            Node* node = root;
            for(char c: word){
                Node*& next = node->next[c-'a'];
                if(!next)
                    next = new Node();
                node = next;
            }
            node->term = true;
        }
        
        /** Returns if the word is in the trie. */
        bool search(string word) {
            Node* node = root;
            for(char c: word){
                node = node->next[c-'a'];
                if(!node)
                    return false;            
            }
            return node->term;
        }
        
        /** Returns if there is any word in the trie that starts with the given prefix. */
        bool startsWith(string prefix) {
            Node* node = root;
            for(char c: prefix){
                node = node->next[c-'a'];
                if(!node)
                    return false;
            }
            return true;
        }
    };
    
    /**
     * Your Trie object will be instantiated and called as such:
     * Trie obj = new Trie();
     * obj.insert(word);
     * bool param_2 = obj.search(word);
     * bool param_3 = obj.startsWith(prefix);
     */
    

    209. Minimum Size Subarray Sum

    Array

    • 双指针
    class Solution {
    public:
        int minSubArrayLen(int s, vector<int>& nums) {
            int len = nums.size()+1;
            int sum = 0;
            int j = 0;
            for(int i=0; i<nums.size(); i++){
                sum += nums[i];
                while(j<i && sum-nums[j]>=s){
                    sum -= nums[j];
                    j++;
                }
                if(sum>=s)
                    len = min(len, i-j+1);
                printf("%d->%d: %d %d\n",j,i,sum,len);
            }
            return len==nums.size()+1 ? 0 : len;
        }
    };
    

    210. Course Schedule II

    • 有其他实现方式
    class Solution {
    public:
        vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
            vector<int> ans;
            unordered_map<int,int> h;
            function<bool(int)> f = [&](int x){
                if(h[x]==1)
                    return true;
                if(h[x]==2)
                    return false;
                h[x] = 1;
                for(auto p: prerequisites)
                    if(p.first==x){
                        if(f(p.second))
                            return true;
                    }
                h[x] = 2;
                ans.push_back(x);
                return false;
            };
            for(int i=0; i<numCourses; i++)
                if(f(i))
                    return {};
            return ans;
        }
    };
    

    211. Add and Search Word - Data structure design

    • Trie (Prefix Tree)
    • DFS
    class WordDictionary {
        struct TrieNode{
            TrieNode* next[26];
            bool term;
            TrieNode(){
                memset(this,0,sizeof(TrieNode));
            }
        };
        TrieNode* root;
    public:
        /** Initialize your data structure here. */
        WordDictionary() {
            root = new TrieNode();
        }
        
        /** Adds a word into the data structure. */
        void addWord(string word) {
            auto node = root;
            for(char c: word){
                auto& next = node->next[c-'a'];
                if(!next)
                    next = new TrieNode();
                node = next;
            }
            node->term = true;        
        }
        
        /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
        bool search(string word) {
            return _search(word.c_str(), root);
        }
        bool _search(const char* s, TrieNode* root){
            for(;;)
                if(*s==0){
                    return root->term;
                }else if(*s=='.'){
                    for(int i=0; i<26; i++){
                        if(root->next[i] && _search(s+1, root->next[i]))
                            return true;
                    }
                    return false;
                }else{
                    root = root->next[*s-'a'];
                    s++;
                    if(root==NULL)
                        return false;
                }
        }
    };
    
    /**
     * Your WordDictionary object will be instantiated and called as such:
     * WordDictionary obj = new WordDictionary();
     * obj.addWord(word);
     * bool param_2 = obj.search(word);
     */
    

    212. Word Search II

    class Solution {
        struct TrieNode{
            TrieNode* next[26];
            const char* term;
            TrieNode(){
                memset(this,0,sizeof(TrieNode));
            }
        };
        TrieNode* root = new TrieNode();
        void insert(string& word) {
            auto node = root;
            for(char c: word){
                auto& next = node->next[c-'a'];
                if(!next)
                    next = new TrieNode();
                node = next;
            }
            node->term = word.c_str();
            printf("> %s\n",node->term);
        }
    public:
        vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
            for(auto& word: words){
                insert(word);
            }
            int m = board.size();
            int n = board[0].size();
            vector<string> ans;
            function<void(int,int,TrieNode*)> f = [&](int y, int x, TrieNode* node){
                char c = board[y][x];
                if(c==0)
                    return;
                auto next = node->next[c-'a'];
                if(next==NULL)
                    return;
                if(next->term){
                    ans.push_back(next->term);
                    next->term = NULL;
                }                
                board[y][x] = 0;
                if(x>0)
                    f(y, x-1, next);
                if(x+1<n)
                    f(y, x+1, next);
                if(y>0)
                    f(y-1, x, next);
                if(y+1<m)
                    f(y+1, x, next);
                board[y][x] = c;
            };
            for(int y=0;y<m;y++){
                for(int x=0;x<n;x++){
                    f(y, x, root);
                }
            }
            return ans;
        }
    };
    

    213. House Robber II

    DP

    class Solution {
        int rob1(vector<int>& nums, int s, int n) {
            if(n==1)
                return nums[s];
            vector<int> d(n);
            d[0] = nums[s];
            d[1] = max(d[0], nums[s+1]);
            for(int i=2; i<n; i++)
                d[i] = max(d[i-1], d[i-2]+nums[s+i]);
            return d[n-1];
        }    
    public:
        int rob(vector<int>& nums) {
            int n = nums.size();
            if(n==0)
                return 0;
            if(n==1)
                return nums[0];
            return max(rob1(nums,0,n-1),rob1(nums,1,n-1));
        }
    };
    
    class Solution {
        int rob1(vector<int>& nums, int s, int n) {
            if(n==1)
                return nums[s];
            int a = 0, b = 0;
            for(int i=0; i<n; i++){
                int c = max(b, a+nums[s+i]);
                a = b;
                b = c;
            }
            return b;
        }    
    public:
        int rob(vector<int>& nums) {
            int n = nums.size();
            if(n==0)
                return 0;
            if(n==1)
                return nums[0];
            return max(rob1(nums,0,n-1),rob1(nums,1,n-1));
        }
    };
    

    214. Shortest Palindrome

    class Solution {
    public:
        string shortestPalindrome(string s) {
            auto s2 = s;
            reverse(s2.begin(),s2.end());
            string m = s + "#" + s2;
            int n = m.size();
            int b[n+1];
            int i = 0, j = -1;
            b[i] = j;
            while(i<n){
                while(j>=0 && m[i]!=m[j])
                    j = b[j];
                i++, j++;
                b[i] = j;
            }
            return s2.substr(0, s.size()-b[n]) + s;
        }
    };
    

    215. Kth Largest Element in an Array

    Sort

    • 题目是查找,用排序
    • quicksort
    • heap
    class Solution {
        int partition(vector<int>& A, int a, int b){
            int pivot = A[b];
            int i = a;
            for(int j=a;j<b;j++)
                if(A[j]<pivot){
                    swap(A[i], A[j]);
                    i++;
                }
            swap(A[i], A[b]);
            return i;
        }
        int search(vector<int>& nums, int a, int b, int k){
            if(a<=b){
                int p = partition(nums, a, b);
                int rest = b - p;
                if(k-1==rest)
                    return nums[p];
                else if(k<=rest)
                    return search(nums, p+1, b, k);    
                else
                    return search(nums, a, p-1, k-rest-1);
            }
            return -1;
        }
    public:
        int findKthLargest(vector<int>& nums, int k) {
            return search(nums, 0, nums.size()-1, k);
        }
    };
    
    class Solution {
        int partition(vector<int>& A, int a, int b){
            int pivot = A[b];
            int i = a;
            for(int j=a;j<b;j++)
                if(A[j]<pivot){
                    swap(A[i], A[j]);
                    i++;
                }
            swap(A[i], A[b]);
            return i;
        }
        int search(vector<int>& nums, int a, int b, int k){
            while(a<=b){
                int p = partition(nums, a, b);
                int rest = b - p;
                if(k-1==rest){
                    return nums[p];
                }else if(k<=rest){
                    a = p+1;
                }else{
                    b = p-1;
                    k = k-rest-1;
                }
            }
            return -1;
        }
    public:
        int findKthLargest(vector<int>& nums, int k) {
            return search(nums, 0, nums.size()-1, k);
        }
    };
    

    216. Combination Sum III

    • 拿前面有道题题小改一下就行
    class Solution {
    public:
        vector<vector<int>> combinationSum3(int k, int n) {
            vector<vector<int>> result;
            int sum = 0;
            vector<int> item;
            function<void(int)> loop = [&](int i){
                if(sum==n && item.size()==k){
                    result.push_back(item);
                    return;
                }
                if(sum>n || item.size()==k)
                    return;
                for(int j=i;j<=9;j++){
                    sum += j;
                    item.push_back(j);
                    loop(j+1);
                    sum -= j;
                    item.pop_back();
                }
            };
            loop(1);
            return result;        
        }
    };
    

    217. Contains Duplicate

    • 这题没意思,是前面的题目的简化版本
    class Solution {
    public:
        bool containsDuplicate(vector<int>& nums) {
            unordered_map<int,bool> h;
            for(int x: nums){
                if(h[x])
                    return true;
                h[x] = true;
            }
            return false;
        }
    };
    

    218. The Skyline Problem

    • 排序拐点
    • 横坐标相同的点先插后删除
    class Solution {
    public:
        vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
             vector<pair<int, int>> ans;
             vector<pair<int, int>> w;
             for(auto& x: buildings){
                 w.push_back({x[0],-x[2]});
                 w.push_back({x[1],x[2]});
             }
             sort(w.begin(),w.end());
             multiset<int> tree = {0};
             int prev = 0;
             for(auto& x: w){
                 if(x.second<0)
                     tree.insert(-x.second);
                 else
                     tree.erase(tree.find(x.second));
                 int top = *tree.rbegin();
                 if(top!=prev){
                    ans.push_back({x.first, top});
                    prev = top;
                 };
             }
             return ans;
        }
    };
    

    219. Contains Duplicate II

    class Solution {
    public:
        bool containsNearbyDuplicate(vector<int>& nums, int k) {
            unordered_map<int,int> h;
            for(int i=0; i<nums.size(); i++){
                auto it = h.find(nums[i]);
                if(it!=h.end() && i-it->second<=k)
                    return true;
                h[nums[i]] = i;
            }
            return false;
        }
    };
    

    220. Contains Duplicate III

    • 滑动窗口
    • 用搜索树,或者哈希表
    class Solution {
    public:
        bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
            multiset<long long> tree;
            for(int i=0; i<nums.size(); i++){
                long x = nums[i];
                if(i-k-1>=0)
                    tree.erase(tree.lower_bound(nums[i-k-1]));
                auto it = tree.lower_bound(x-t);
                if(it!=tree.end() && distance(it, tree.upper_bound(x+t))>0)
                    return true;
    
                tree.insert(nums[i]);
            }
            return false;
        }
    };
    
    • lower_bound 返回大于等于的元素
    class Solution {
    public:
        bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
            multiset<long long> tree;
            for(int i=0; i<nums.size(); i++){
                long x = nums[i];
                if(i-k-1>=0)
                    tree.erase(tree.lower_bound(nums[i-k-1]));
                auto it = tree.lower_bound(x-t);
                if(it!=tree.end() && *it<=x+t)
                    return true;
                tree.insert(nums[i]);
            }
            return false;
        }
    };
    

    221. Maximal Square

    • 挺标准的动态规划的题目
      • 非常标准
      • 画图推演一下
    class Solution {
    public:
        int maximalSquare(vector<vector<char>>& matrix) {
            int m = matrix.size();
            if(m==0)
                return 0;
            int n = matrix[0].size();
            int ans = 0;
            vector<int> d(n, 0);
            for(int x=0;x<n;x++)
                if(matrix[0][x]-'0')
                    ans = d[x] = 1;
            for(int y=1;y<m;y++){
                int c = d[0];
                d[0] = matrix[y][0]-'0';
                ans = max(ans, d[0]);
                for(int x=1;x<n;x++){
                    int t = d[x];
                    if(matrix[y][x]-'0'){
                        d[x] = min(c, min(d[x], d[x-1]))+1;
                        ans = max(ans, d[x]);
                    }else{
                        d[x] = 0;
                    }
                    c = t;
                }
            }
            return ans*ans;
        }
    };
    

    222. Count Complete Tree Nodes

    • 很容易超时
    • 利用题目中完全二叉树的性质做优化
    • 满二叉树有 2^k-1 个节点
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        int countNodes(TreeNode* root) {
            int d1 = 0, d2 = 0;
            for(auto p=root; p; p=p->left)
                d1++;
            for(auto p=root; p; p=p->right)
                d2++;
            if(d1==d2)
                return pow(2, d1)-1;
            else
                return countNodes(root->left)+countNodes(root->right)+1;        
        }
    };
    

    223. Rectangle Area

    • 计算两个矩形的总面积
    • 可能有重叠部分
    class Solution {
    public:
        int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
            int I = max(A,E), J = max(B,F), K= min(C,G), L=min(D,H);
            return (C-A)*(D-B)+(G-E)*(H-F)-( K>I && L>J ?(K-I)*(L-J) : 0);
        }
    };
    

    224. Basic Calculator

    class Solution {
        int priority(char c){
            switch(c){
                case '+':
                case '-':
                    return 1;
                case '*':
                case '/':
                    return 2;
                default:
                    return 0;
            }
        }
        void operate(){
            int y = nums.top();
            nums.pop();
            int x = nums.top();
            nums.pop();
            switch(ops.top()){
                case '+':
                    nums.push(x+y);
                    break;
                case '-':
                    nums.push(x-y);
                    break;
                case '*':
                    nums.push(x*y);
                    break;            
                case '/':
                    nums.push(x/y);
                    break;
            }
            ops.pop();
        }
        stack<int> nums;
        stack<char> ops;    
    public:
        int calculate(string s) {
            char c;
            const char *p = s.c_str();
            while((c=*p)){
                printf("> %c\n",c);
                switch(c){
                    case ' ':
                        p++;
                        break;
                    case '+':
                    case '-':
                    case '*':
                    case '/':
                        while(!ops.empty() && priority(c)<=priority(ops.top()))
                            operate();
                        ops.push(c);
                        p++;
                        break; 
                    case '(':
                        ops.push(c);
                        p++;
                        break;
                    case ')':
                        while(ops.top()!='(')
                            operate();
                        ops.pop();
                        p++;
                        break;
                    default:
                        char *e;
                        int x = strtol(p, &e, 10);
                        nums.push(x);
                        p = e;
                }
            }
            while(!ops.empty())
                operate();
            return nums.top();
        }
    };
    
    • 没有乘除法,只有加减和正整数,可以简化
    • 求和,带符号
    class Solution {
    public:
        int calculate(string s) {
            int ans = 0;
            stack<int> signs;
            signs.push(1);
            int sign = 1;
            const char *p = s.c_str();
            char c;        
            for(;;){
                switch(*p){
                    case 0:
                        goto end_for;
                    case ' ':
                        p++;
                        break;
                    case '+':
                        sign = 1;
                        p++;
                        break;
                    case '-':
                        sign = -1;
                        p++;
                        break; 
                    case '(':
                        signs.push(sign*signs.top());
                        sign = 1;
                        p++;
                        break;
                    case ')':
                        signs.pop();
                        sign = 1;
                        p++;
                        break;
                    default:
                        char *e;
                        int x = strtol(p, &e, 10);
                        ans += signs.top()*sign*x;
                        p = e;
                }
            }
            end_for:
            return ans;
        }
    };
    

    225. Implement Stack using Queues

    • 可以用 size(queue)
    • 出入有一个操作为 O(N)
    • 可以不需要额外空间
    class MyStack {
        queue<int> q1, q2;
    public:
        /** Initialize your data structure here. */
        MyStack() {
            
        }
        
        /** Push element x onto stack. */
        void push(int x) {
            q2.push(x);
        }
        
        /** Removes the element on top of the stack and returns that element. */
        int pop() {
            while(q2.size()>1){
                q1.push(q2.front());
                q2.pop();
            }
            int y = q2.front();
            q2.pop();
            q1.swap(q2);
            return y;
        }
        
        /** Get the top element. */
        int top() {
            int y = pop();
            q2.push(y);
            return y;
        }
        
        /** Returns whether the stack is empty. */
        bool empty() {
            return q2.empty();
        }
    };
    
    /**
     * Your MyStack object will be instantiated and called as such:
     * MyStack obj = new MyStack();
     * obj.push(x);
     * int param_2 = obj.pop();
     * int param_3 = obj.top();
     * bool param_4 = obj.empty();
     */
    

    226. Invert Binary Tree

    • 二叉树遍历
    class Solution {
    public:
        TreeNode* invertTree(TreeNode* root) {
            if(root==nullptr)
                return nullptr;
            swap(root->left, root->right);
            invertTree(root->left);
            invertTree(root->right);
            return root;
        }
    };
    

    227. Basic Calculator II

    • 前面那题的特例/子集
    • 不叫优化,叫简化/特殊化
    int calculate(char* s) {
        int ans = 0;
        int x = strtol(s,&s,10);
        while(*s){
            while(isspace(*s))
                s++;
            char op = *s++;
            int y = strtol(s,&s,10);
            switch(op){
                case '+':
                    ans += x;
                    x = y;
                    break;
                case '-':
                    ans += x;
                    x = -y;
                    break;
                case '*':
                    x *= y;
                    break;
                case '/':
                    x /= y;
                    break;
            }
        }
        ans += x;
        return ans;
    }
    
    class Solution {
    public:
        int calculate(string s) {
            stack<int> st;
            int x;
            const char *p = s.c_str();
            st.push(strtol(p,(char**)&p,10));
            while(*p){
                while(isspace(*p))
                    p++;
                char op = *p++;
                int x, y = strtol(p,(char**)&p,10);
                switch(op){
                    case '+':
                        st.push(y);
                        break;
                    case '-':
                        st.push(-y);
                        break;
                    case '*':
                        x = st.top();
                        st.pop();
                        st.push(x*y);
                        break;
                    case '/':
                        x = st.top();
                        st.pop();
                        st.push(x/y);                
                        break;
                }
            }
            int ans = 0;
            while(!st.empty()){
                ans += st.top();
                st.pop();
            }
            return ans;
        }
    };
    

    228. Summary Ranges

    class Solution {
    public:
        vector<string> summaryRanges(vector<int>& nums) {
            vector<string> ans;
            stringstream b;
            int s = 0;
            for(int i=1; s!=nums.size(); i++){
                if(i==nums.size() || nums[i]!=nums[i-1]+1){
                    if(s==i-1){
                        ans.push_back(to_string(nums[i-1]));
                    }else{
                        stringstream b;
                        b << nums[s] << "->" << nums[i-1];
                        ans.push_back(b.str());
                    }
                    s = i;
                }
            }
            return ans;
        }
    };
    

    229. Majority Element II

    class Solution {
    public:
        vector<int> majorityElement(vector<int>& nums) {
            int a = 0, ca = 0;
            int b = 0, cb = 0;
            for(int x: nums){
                if(x==a){
                    ca++;
                }else if(x==b){
                    cb++;
                }else if(ca==0){
                    a = x, ca = 1;
                }else if(cb==0){
                    b = x, cb = 1;
                }else{
                    cb--, ca--;
                }
            }
            ca = cb = 0;
            for(int x: nums){
                if(x==a)
                    ca++;
                else if(x==b)
                    cb++;
            }
            vector<int> ans;
            if(ca>nums.size()/3)
                ans.push_back(a);
            if(cb>nums.size()/3)
                ans.push_back(b);
            return ans;
        }
    };
    

    230. Kth Smallest Element in a BST

    Tree

    • 这题本身没什么,附加问挺有意思的
    • 依然基于排序二叉树的模版,针对题目做适当的优化
      • 在二叉树添加和查找的时候,在每个节点维持做节点个数。
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
        int count = 0;
        int ans;
        bool f(TreeNode* root){
            if(!root)
                return false;
            if(f(root->left))
                return true;
            count--;
            if(count==0){
                ans = root->val;
                return true;
            }
            if(f(root->right))
                return true;
            return false;
        }
    public:
        int kthSmallest(TreeNode* root, int k) {
            count = k;
            f(root);
            return ans;
        }
    };
    

    231. Power of Two

    • 是 2, 4, 8, 16, 32, 64 ...
    • 利用二进制中 1 的个数的那题,判断最高位
    class Solution {
    public:
        bool isPowerOfTwo(int n) {
            return n>0 && !(n&(n-1));
        }
    };
    

    232. Implement Queue using Stacks

    Stack

    • 在函数式不可变的数据结构中用得到
    class Queue {
        stack<int> s1;
        stack<int> s2;
        void enq(){
            while(!s2.empty()){
                s1.push(s2.top());
                s2.pop();
            }
        }
    public:
        // Push element x to the back of queue.
        void push(int x) {
            s2.push(x);
        }
    
        // Removes the element from in front of queue.
        void pop(void) {
            if(s1.empty())
                enq();
            s1.pop();
        }
    
        // Get the front element.
        int peek(void) {
            if(s1.empty())
                enq();
            return s1.top();
        }
    
        // Return whether the queue is empty.
        bool empty(void) {
            return s1.empty() && s2.empty();
        }
    };
    

    233. Number of Digit One

    Integer

    class Solution {
    public:
        int countDigitOne(int n) {
            int a=0, b=1, c=1;
            while(n){
                a += (n + 8) / 10 * b; 
                if(n%10==1)
                    a += c;
                c += (n%10)*b;
                b *= 10;
                n /= 10;
            }
            return a;
        }
    };
    

    234. Palindrome Linked List

    • 拿前面有道链表题改改就行
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
        ListNode* cut(ListNode* head){
            if(!head)
                return NULL;
            auto slow = head, fast = head;
            while(fast && fast->next && fast->next->next){
                slow = slow->next;
                fast = fast->next->next;
            }
            auto head2 = slow->next;
            slow->next;
            return head2;
        }
        ListNode* reverse(ListNode* head){
            ListNode* prev = NULL;
            while(head){
                auto next = head->next;
                head->next = prev;
                prev = head;
                head = next;
            }
            return prev;        
        }
    public:
        bool isPalindrome(ListNode* head) {
            auto head2 = reverse(cut(head));
            for(auto p=head,q=head2; p&&q; p=p->next,q=q->next)
                if(p->val!=q->val)
                    return false;
            return true;
        }
    };
    

    235. Lowest Common Ancestor of a Binary Search Tree

    • 已知根节点
    • 利用二叉排序树的节点值的关系
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            for(;;)
                if(root->val > p->val && root->val > q->val){
                    root = root->left;
                }else if(root->val < p->val && root->val < q->val){
                    root = root->right;
                }else{
                    return root;
                }
        }
    };
    

    236. Lowest Common Ancestor of a Binary Tree

    • 递归,验证左右节点是否为父节点
      • 都不是,则自己是
      • 有一个是,在那边
    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
     * };
     */
    class Solution {
    public:
        TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
            if(!root || root==p || root==q)
                return root;
            auto left = lowestCommonAncestor(root->left, p, q);
            auto right = lowestCommonAncestor(root->right, p, q);
            if(left && right)
                return root;
            return left ? left : right;
        }
    };
    

    237. Delete Node in a Linked List

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        void deleteNode(ListNode* node) {
            auto next = node->next;
            assert(next);
            *node = *next;
            delete next;
        }
    };
    

    238. Product of Array Except Self

    • 题目要求不用除法,那就左右来回两趟
      • 左边乘以右边
    class Solution {
    public:
        vector<int> productExceptSelf(vector<int>& nums) {
            int n = nums.size();
            vector<int> ans(n);
            int c = 1;
            for(int i=0; i<n; i++){
                ans[i] = c;
                c *= nums[i];
            }
            c = 1;
            for(int i=n-1; i>=0; i--){
                ans[i] *= c;
                c *= nums[i];
            }
            return ans;
        }
    };
    

    239. Sliding Window Maximum

    class Solution {
    public:
        vector<int> maxSlidingWindow(vector<int>& nums, int k) {
            if(nums.size()<k || k==0)
                return {};
            vector<int> m;
            deque<int> q;
            for(int i=0; i<k; i++){
                while(!q.empty() && nums[i]>=nums[q.back()])
                    q.pop_back();
                q.push_back(i);
            }
            for(int i=k; i<nums.size(); i++){
                m.push_back(nums[q.front()]);
                while(!q.empty() && nums[i]>=nums[q.back()])
                    q.pop_back();
                while(!q.empty() && q.front()<=i-k)
                    q.pop_front();
                q.push_back(i);
            }
            m.push_back(nums[q.front()]);
            return m;
        }
    };
    

    240. Search a 2D Matrix II

    • 从右上角/左下角开始搜索,往左下/右上方向进行
    class Solution {
    public:
        bool searchMatrix(vector<vector<int>>& matrix, int target) {
            int m = matrix.size();
            if(m==0)
                return false;
            int n = matrix[0].size();
            int x = n-1, y=0;
            while(y<m && x>=0){
                if(matrix[y][x]==target){
                    return true;
                }if(matrix[y][x]<target)
                    y++;
                else{
                    x--;
                }
            }
            return false;
        }
    };
    

    241. Different Ways to Add Parentheses

    Search

    • 表达式语法树,这里是二叉树
      • 每个符号都有机会做根节点
    • 不要遗漏解,挺容易遗漏的
    • 求全部解,笛卡尔积
      • 递归函数返回数组,或者使用回调
      • 存在左右子树两个方向,都各有若干可能
        • 这是这道题有趣的地方
    class Solution {
        const char* s;
        void f(int a, int b, function<void(int)> c){
            bool flag = false;
            for(int i=a; i<=b; i++){
                switch(s[i]){
                    case '+':
                        flag = true;
                        f(a,i-1,[&](int x){
                            f(i+1,b,[&](int y){
                                c(x+y);
                            });
                        });
                        break;
                    case '-':
                        flag = true;
                        f(a,i-1,[&](int x){
                            f(i+1,b,[&](int y){
                                c(x-y);
                            });
                        });                
                        break;
                    case '*':
                        flag = true;
                        f(a,i-1,[&](int x){
                            f(i+1,b,[&](int y){
                                c(x*y);
                            });
                        });                
                        break;
                }
            }
            if(!flag){
                c(strtol(s+a,0,10));
            }
        }
    public:
        vector<int> diffWaysToCompute(string input) {
            vector<int> ans;
            this->s = input.c_str();
            f(0,input.size()-1,[&](int z){
                ans.push_back(z);
            });
            return ans;
        }
    };
    

    242. Valid Anagram

    • 排序,或者哈希
    class Solution {
    public:
        bool isAnagram(string s, string t) {
            sort(s.begin(), s.end());
            sort(t.begin(), t.end());
            return s==t;
        }
    };
    
    class Solution {
    public:
        bool isAnagram(string s, string t) {
            unordered_map<char,int> h;
            for(char x: s)
                h[x]++;
            for(char x: t)
                h[x]--;
            for(auto p: h)
                if(p.second)
                    return false;
            return true;
        }
    };
    

    索引

    归类

    解答 1.5

    有锁的题放这里

    解答 2

    以下用来尝试一些不那么好的解法。

    有的是不符合题目的全部要求,有的就是随手写写的。

    部分题目的解答

    用 Ruby

    扩展想法用,写一些并不一定完全复合题目要求。

    注意

    • Ruby 负数除法的取整方向和 C 不一样

    1. Two Sum

    • array + hash
    def two_sum(nums, target)
      h = {}
      for x, i in nums.each_with_index
        return h[x], i if h.key? x
        h[target-x] = i
      end
    end
    

    2. Add Two Numbers

    def add_two_numbers(l1, l2)
        list = node = ListNode.new(nil)
        c = 0
        while l1 || l2 || c!=0
            if l1
                c += l1.val
                l1 = l1.next
            end
            if l2
                c += l2.val
                l2 = l2.next
            end
            node.next = ListNode.new(c%10)
            c /= 10
            node = node.next
        end
        list.next
    end
    

    3. Longest Substring Without Repeating Characters

    # @param {String} s
    # @return {Integer}
    def length_of_longest_substring(s)
      ans = 0
      h = Hash.new(-1)
      j = -1
      for c, i in s.each_char.with_index
        j = [j, h[c]].max
        h[c] = i
        ans = [ans, i-j].max
      end
      ans
    end
    

    17. Letter Combinations of a Phone Number

    • 回溯
    • 这题每一步不需要加条件,后面的回溯题会先过滤路径上的点。
    • 回溯的每一项是“或”的关系
    # @param {String} digits
    # @return {String[]}
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        f = ->(s){
            if s.empty?
                [""]
            else
                h[s[0].to_i].chars.flat_map{|x|
                    f.(s[1..-1]).map{|y|
                        x+y
                    }
                }
            end
        }
        digits.empty? ? [] : f.(digits)
    end
    
    # @param {String} digits
    # @return {String[]}
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        f = ->(i){
            if i==digits.size
                [""]
            else
                h[digits[i].to_i].chars.flat_map{|x|
                    f.(i+1).map{|y|
                        x+y
                    }
                }
            end
        }
        digits.empty? ? [] : f.(0)
    end
    

    上面这个以后删掉

    # @param {String} digits
    # @return {String[]}
    def letter_combinations(digits)
        return [] if digits.empty?
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        ans = []
        path = []
        f = ->(i){
            if i==digits.size
                ans.push path*''
            else
                for c in h[digits[i].to_i].chars
                    path.push c
                    f.(i+1)
                    path.pop
                end
            end
        }
        f.(0)
        ans
    end
    

    写成用 Stack 的形式

    # @param {String} digits
    # @return {String[]}
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        ans = []
        stack = []
        stack.push(-1)
        while !stack.empty?
            stack[-1] += 1
            p stack
            if stack[-1]>=h[digits[stack.size-1].to_i].size
                stack.pop
            elsif stack.size==digits.size
                ans.push stack.map.with_index{|x,i|
                    h[digits[i].to_i][x]
                }*''
            else
                stack.push(-1)
            end
        end
        ans
    end
    
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        return [] if digits.empty?
        ans = []
        stack = []
        stack.push(-1)
        path = []
        while x = stack.pop
            if stack.size==digits.size
                ans.push path*''
                path.pop
                next
            end
            x += 1
            if x>=h[digits[stack.size].to_i].size
                path.pop
            else
                path.push(h[digits[path.size].to_i][x])
                stack.push(x)
                stack.push(-1)
            end
        end
        ans
    end
    
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        return [] if digits.empty?
        ans = []
        stack = []
        stack.push(-1)
        path = []
        while !stack.empty?
            if stack.size>digits.size
                ans.push path*''
                path.pop
                stack.pop
                next
            end
            stack[-1] += 1
            if stack[-1]>=h[digits[stack.size-1].to_i].size
                path.pop
                stack.pop
            else
                path.push(h[digits[path.size].to_i][stack[-1]])
                stack.push(-1)
            end
        end
        ans
    end
    
    def letter_combinations(digits)
        h = ["","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
        return [] if digits.empty?
        ans = []
        stack = []
        stack.push(-1)
        path = []
        while !stack.empty?
            if stack.size>digits.size
                ans.push path*''
                stack.pop
                next
            end
            o = stack[-1]
            stack[-1] += 1
            if stack[-1]>=h[digits[stack.size-1].to_i].size
                path.pop if o!=-1
                stack.pop
            else
                path.pop if o!=-1
                path.push(h[digits[path.size].to_i][stack[-1]])
                stack.push(-1)
            end
        end
        ans
    end
    

    38. Count and Say

    def count_and_say(n)
        (n-1).times.inject("1"){|a,b|a.chars.chunk(&:itself).map{|k,v|"#{v.size}#{k}"}*''}
    end
    

    49. Group Anagrams

    def group_anagrams(strs)
        strs.group_by{|x|x.chars.sort}.values
    end
    

    51. N-Queens

    def solve_n_queens(n)
      a = [nil]*n
      b = [false]*n
      c = [false]*(2*n-1)
      d = [false]*(2*n-1)
      ys = []
      f = ->(i){
        if i < n
          for j in 0...n
            unless b[j] || c[i+j] || d[i-j+n-1]
              a[i] = j
              b[j] = c[i+j] = d[i-j+n-1] = true
              f.(i + 1)
              b[j] = c[i+j] = d[i-j+n-1] = false
            end
          end
        else
          ys << a.collect{|x|
              line = "."*n
              line[x] = ?Q
              line
          }
        end
      }
      f[0]
      ys
    end
    

    65. Valid Number

    def is_number(s)
        s=~/^\s*[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?\s*$/ ? true : false;
    end
    

    66. Plus One

    def plus_one(digits)
        (digits.size-1).downto(0) do |i|
            if(digits[i]!=9)
                digits[i] += 1
                return digits
            end
            digits[i] = 0
        end
        digits.unshift(1)
        return digits
    end
    

    78. Subsets

    def subsets(nums)
        (1<<nums.length).times.map{|i|nums.select.with_index{|x,j|(i>>j)&1==1}}
    end
    

    94. Binary Tree Inorder Traversal

    def inorder_traversal(root)
        result = []
        stack = []
        node = root
        while node || !stack.empty?
            if node
                stack << node
                node = node.left
            else
                node = stack.pop
                result << node.val
                node = node.right
            end
        end
        result
    end
    
    def inorder_traversal(root)
        result = []
        stack = []
        node = root
        while true
            if node
                stack << node
                node = node.left
            elsif !stack.empty?
                node = stack.pop
                result << node.val
                node = node.right
            else
                break
            end
        end
        result
    end
    

    102. Binary Tree Level Order Traversal

    • 二叉树层次遍历
    def level_order(root)
        result = []
        queue = []
        queue << root if root
        until queue.empty?
            result << queue.map(&:val)
            queue.size.times do
                node = queue.shift
                queue << node.left if node.left
                queue << node.right if node.right
            end
        end
        result
    end
    

    144. Binary Tree Preorder Traversal

    def preorder_traversal(root)
        result = []
        stack = []
        stack << root if root
        while node = stack.pop
            result << node.val
            stack << node.right if node.right
            stack << node.left if node.left
        end
        result
    end
    

    145. Binary Tree Postorder Traversal

    def postorder_traversal(root)
        result = []
        stack = []
        node = root
        prev = nil
        while true
            if node
                stack << node
                node = node.left
            elsif !stack.empty?
                node = stack.last
                if prev==node.right || node.right.nil?
                    result << node.val
                    prev, node = node, nil
                    stack.pop
                else
                    node = node.right
                end
            else
                break
            end
        end
        result
    end
    

    208. Implement Trie (Prefix Tree)

    class Trie
    
        def initialize()
            @root = {}
        end
    
        def insert(word)
            node = @root
            word.each_char do |c|
                node = node[c]||={}
            end
            node[nil] = true        
        end
    
        def search(word)
            node = @root
            word.each_char do |c|
                node = node[c] or return false
            end
            node[nil]==true
        end
    
        def starts_with(prefix)
            node = @root
            prefix.each_char do |c|
                node = node[c] or return false
            end
            true
        end
    
    end
    

    217. Contains Duplicate

    def contains_duplicate(nums)
        h = {}
        nums.each do |e|
            return true if h[e]
            h[e] = true
        end
        false
    end
    
    def contains_duplicate(nums)
        nums.sort!
        for i in 1...nums.size
            return true if nums[i]==nums[i-1]
        end
        false
    end
    

    224. Basic Calculator

    def calculate(s)
        ans = 0
        stack = [1]
        sign = 1
        s.scan(/\d+|[+\-()]/) do |x|
            case x
            when ?+
                sign = stack.last
            when ?-
                sign = -stack.last
            when ?(
                stack << sign
                sign = stack.last
            when ?)
                stack.pop
            else
                ans += sign*x.to_i
            end
        end
        ans
    end
    

    227. Basic Calculator II

    def calculate(s)
        ans = 0
        e = s.scan(/\d+|[+\-*\/]/)
        x = e.shift.to_i
        while op = e.shift
            y = e.shift.to_i
            case op
            when ?+
                ans += x
                x = y
            when ?-
                ans += x
                x = -y
            when ?*
                x *= y
            when ?/
                x = x.fdiv(y).to_i
            end
        end
        ans += x
    end
    

    解答3

    Java 和 JavaScript

    分类

    C++11

    • 在 OJ 中 C++98 支持得最广泛

      • 出于速度和输出格式的考虑,用 printf
      • 目前 LeetCode 中用的是 C++11
    • LeetCode 的有些题目是针对 C++/Java 设计的

    • C 中字符串指针在 C++ 中只读时可以使用,可以转换为用下标

      • 数组也可以用指针,vector 只能用下标了。
      • C 的字符串后缀是递归的数据结构
    • 比 C++98 多了 hashtable

      • 有的情况可以用排序
        • 二分法查找
        • 重复元素相邻排列
      • 或者用数组
        • key 少的时候用下标
        • 线性探测法,特别是不删,有限的时也挺简单
    • vector尽量预先分配大小

    • 有 move 之后可以直接返回 vector 了

    • 比 Java 多了引用,链表问题中 next 的指针可以转换为添加一个头节点

    • 和 Python 相比,有大括号和分号

    • 内存管理,C++ 没有 Java 的 GC,相比 C 有 C++ 可以利用作用域

      • 算法题可以利用程序结束释放所有内存
    • IO 函数 C 比 C++ 快,所以为了充分利用运行时间,尽量用 C 的

    • 死循环或者复杂度太高会超时,下标越界或空指针会运行时错误

      • 越界错误有时候本地会继续运行会未报错
    • STL

      • C 的 string,qsort,bsearch
    • 假设 Accepted 的解答为结果正确的解答

      • LeetCode 有的题目在提交后会又有改动
      • 原先 C++ 参数传数组改为用 STL
      • 有个解答原来不超时的变得超时了
    • freebsd 可以看一些标准库的实现

    • 感觉最初 LeetCode 是一个可以刷题的 Blog

    • 提交结果

      • Runtime Error 越界,爆栈,空指针
        • 后来开始返回错误信息了。。。
      • Time Limit Exceeded 复杂度,死循环
    • 参考资料

    注意

    • 考虑边界情况和异常情况
      • 递归溢出
    • 自行设计测试用例,更多情况不像 LeetCode 有提供的可以依赖
    • 死循环的时候 Debug
    • 使用 printf scanf
    • 分析题干中的要求,运用基本的模型,分解为步骤的组合
      • 有时候题目对输入有限定
    • 用符合题目要求的,比较好实现的解答就可以了
      • .size() 为 unsigned,-1 会不对

    整数

    • 32位补码有符号整数范围 $[-2{31},2{31}-1]$ ,最小负数取相反数会溢出
    • 在 C 中负数取模为负数,不同语言有不同规则
    • 负数右移是除以2向下取整数,除法是向零取整数。
    • 有符号,无符号位移

    数组/链表

    • 数组和链表都可以按顺序访问

      • 数组还可以按下标随机读写
      • 链表有节点指针变换的问题
    • 插入排序,选择排序

    链表

    • 有时候可以构建一个额外的头结点
    • 注意元素个数为 0, 1, 2 的情况

    栈,队列

    • 可以用数组和链表实现

    二叉树

    • 递归遍历能应对大部分问题

    • 有些状态机可以作为图

    • 深度优先搜索用 Stack,广度优先搜索用 Queue

      • 取出元素时处理
      • 将相邻节点插入
        • 有环图已搜索过的相邻节点不再插入
    • 最短路径

      • 举例为 1 时 变成广度优先搜索
      • 使用优先级队列

    查找

    • 二分查找

    排序

    递归/回溯

    • 典型问题
      • 八皇后
      • 排列组合
      • 深度优先搜索
    • 短路可以通过检查返回值快速返回
    • 递归用栈写成迭代形式,并不能降低复杂度。
      • 对提交代码的结果没有影响,除非题目对实现方案有特定要求

    逻辑/搜索

    排列组合

    • 使用回溯法解答,通常写成递归形式
    • 集合是无序的
    • 全排列中升序的序列构成组合
    • 有重复元素时,重复元素的顺序改变同一个排列
    • 集合元素可以用转换为用下标(索引)表示

    动态规划

    重叠

    字符串

    • 作为数组问题处理
    • 实现 strstr 函数

    质数

    • 因式分解

    C 语言

    有些 C 语言的问题没在数据结构书中出现,也有出现的

    • memmove

    相关文章

      网友评论

      • bearpawow:你好,我觉得你写的很有帮助,才看了一点点。有一点不太理解的,在第二个add two numbers里,请问“大数”是什么意思呢?

      本文标题:LeetCode

      本文链接:https://www.haomeiwen.com/subject/qfagnttx.html