LeetCode

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
    原文作者:蕾娜漢默
    原文地址: https://www.jianshu.com/p/541b8981b692
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞