力扣部分刷题记录

1. 两数之和

思路:

暴力遍历

代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        
        int lenNums = nums.size();
        int a, b;
        for(int i = 0; i < lenNums; i ++){
            for(int j = i + 1; j < lenNums; j ++){
                if(nums[i] + nums[j] == target){
                    vector<int> res;
                    res.push_back(i);
                    res.push_back(j);
                    return res;
                }
            }
        }
    vector<int> res;
    return res;
    }
    
};

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 * res = new ListNode();
        ListNode * h = res;
        int c = 0;
        while(l1 || l2){
            int x = 0;
            if(l1) x += l1->val;
            if(l2) x += l2->val;
            x += c;
            //cout << " x= " << x << endl;
            h->next = new ListNode(x % 10);
            c = x / 10;
            h = h->next;
            if(l1) l1 = l1->next;
            if(l2) l2 = l2->next;
        }
        if(c){
            h->next = new ListNode(1);
        }
        return res->next;
    }
};

3. 无重复字符的最长子串

思路:

暴力:
    枚举每一个字符,当做当前子串的头,依次遍历下去,直到不合格。
那么显然是要超时的,在暴力的基础做一个小优化即可:
    当我们枚举s[i]为头部的时候,遍历到s[j]发现,s[j]在[i, j]之间出现过,我们用一个map来记录字符最新的位置,那么显然在 [m[s[j]] + 1, j]这之中是没有重复字符出现的,利用这个技巧可以在线性时间内解决。

代码:

class Solution {
public:
    int lengthOfLongestSubstring(string s) {

        int res = 0, cur = 0, idx = 0;
        int lenS = s.size();
        map<char, int> mp;
        for(int i = 0; i < lenS; i ++){
            if(mp[s[i]] && mp[s[i]] > idx){
                res = max(res, cur);
                cur = i - mp[s[i]] + 1;
                idx = mp[s[i]];
                mp[s[i]] = i + 1;
            } else{
                mp[s[i]] = i + 1;
                cur ++;
            }
        }
        return max(res, cur);

    }
};

4. 寻找两个正序数组的中位数

思路:

二分。
分奇偶来讨论,每次寻找两个数组中第(k / 2 - 1) 个元素,很明显小的那个不符合要求,所以他前面的包括他都可以删去,用指针来实现。特判特殊情况即可。

代码:

class Solution {
public:

    int find(vector<int> a, vector<int> b, int k){
        int la = a.size();
        int lb = b.size();
        int idxA = 0, idxB = 0;
        while(1){
            if(idxA == la) return b[idxB + k - 1];
            if(idxB == lb) return a[idxA + k - 1];
            if(k == 1) return min(a[idxA], b[idxB]);
            
            int newIdxA = min(idxA + k / 2 - 1, la - 1);
            int newIdxB = min(idxB + k / 2 - 1, lb - 1);
            
            if(a[newIdxA] <= b[newIdxB]){
                k -= newIdxA - idxA + 1;
                idxA = newIdxA + 1;
            } else{
                k -= newIdxB - idxB + 1;
                idxB = newIdxB + 1;
            }

        }
    }

    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        
        int all = nums1.size() + nums2.size();
        double res;
        if(all & 1) res = find(nums1, nums2, all / 2 + 1);
        else res = (find(nums1, nums2, all / 2) + find(nums1, nums2, all / 2 + 1)) / 2.0;
        return res;

    }
};

5. 最长回文子串

思路:

用Manacher算法求出最长回文串的长度和其中心的下标即可。

代码:

class Solution {
public:
    
    pair<int, int> Manacher(char * s, int len){
        int p[2010];
        int maxLen = 0, maxId;
        int mx = 0, id = 1;
        for(int i = 1; i <= len; i ++){
            if(mx > i) p[i] = min(p[2 * id - i], mx - i);
            else p[i] = 1;
            while(i + p[i] <= len && s[i + p[i]] == s[i - p[i]]) p[i] ++;
            if(p[i] >= mx) { mx = p[i]; id = i; }
            if(maxLen < p[i] - 1){
                maxLen = p[i] - 1;
                maxId  = i;
            }
        }
        return {maxLen, maxId};
    }
    
    string longestPalindrome(string s) {
        char str[2010];
        int lenStr = 0;
        for(int i = 0; i < s.size(); i ++){
            str[ ++ lenStr] = '~';
            str[ ++ lenStr] = s[i];
        }
        str[ ++ lenStr] = '~';
        pair<int, int> ans = Manacher(str, lenStr);
        int a = ans.first;
        int b = ans.second;
        cout << a << " " << b << endl;
        string res = "";
        for(int i = b - a + 1; i < b + a; i ++){
            if(str[i] == '~') continue;
            res += str[i];
        }
        return res;
    }
};

6. Z 字形变换

思路:

找规律。
设 m = 2 * numRows - 2;
那么遍历去 % m 很容易发现规律

代码:

class Solution {
public:
    string convert(string s, int numRows) {
        if(numRows == 1) return s;
        int len = s.size();
        vector<string> tmp(numRows);
        string res = "";
        int m = 2 * numRows - 2;
        for(int i = 0; i < len; i ++){
            int t = i % m;
            if(t < numRows) tmp[t].push_back(s[i]);
            else tmp[m - t].push_back(s[i]);
        }
        for(int i = 0; i < tmp.size(); i ++)
            res += tmp[i];
        return res;
    }
};

7. 整数反转

思路:

注意溢出

代码:

class Solution {
public:
    int reverse(int x) {
        
        long long res = 0;
        long long mx  = (1ll << 31) - 1;
        long long mn  = - (1ll << 31);
        int mark = 0;
        if(x < 0){
            mark = 1;
            if(x == mn) x = 0;
            else x *= -1;
        }
        while(x){
            res = res * 10 + x % 10;
            x /= 10;
        }
        if(mark) res *= -1;
        if(res > mx || res < mn) res = 0;
        return int(res);
    }
};

8. 字符串转换整数 (atoi)

思路:

模拟即可

代码:

class Solution {
public:
    int myAtoi(string str) {
        int lenStr = str.size();
        string s = "";
        int symbol = 0; // 记录符号
        int flag = 0;
        for(int i = 0; i < lenStr; i ++){
            if(!flag && str[i] == ' ') continue;
            else{
                if(str[i] >= '0' && str[i] <= '9')
                    s += str[i];
                else if(!flag && str[i] == '-')
                    symbol = -1;
                else if(!flag && str[i] == '+')
                    symbol = 1;
                else break;
                flag = 1;
            }
        }
        if(s.empty()) return 0;
        long long num = 0;
        for(int i = 0; i < s.size(); i ++) {
            num = num * 10 + (s[i] - '0');
            if(num > INT_MAX) break;
        }
        if(symbol == -1) num *= -1;
        if(num > INT_MAX) num = INT_MAX;
        if(num < INT_MIN) num = INT_MIN;
        return int(num);
        return 0;
    }
};

9. 回文数

思路:

暴力

代码:

class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0) return false;
        long long y = 0;
        int tmp = x;
        while(x){
            y = y * 10 + x % 10;
            x /= 10;
        }
        return y == tmp;
    }
};

10. 正则表达式匹配

思路:

二维DP
设f[i][j]: s中前i个字符与p中前j个字符是否合法匹配
    1. p[j] = '*':
    	f[i][j] |= f[i][j - 2]	// 将j-1删去
    	if(p[j - 1] == s[i]) f[i][j] |= f[i - 1][j]
    2. p[j] != '*':
		if(p[j] == '.' || p[j] == s[i]) f[i][j] |= f[i - 1][j - 1]
return f[size(s)][size(p)]

代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        int ls = s.size();
        int lp = p.size();
        auto check = [&](int i, int j){
            if(i == 0) return false;
            if(p[j - 1] == '.' || p[j - 1] == s[i - 1]) return true;
            return false;
        };
        
        int f[ls + 10][lp + 10];
        memset(f, 0, sizeof f);
        f[0][0] = true;
        for(int i = 0; i <= ls; i ++)
            for(int j = 1; j <= lp; j ++){
                if(p[j - 1] == '*'){
                    if(j >= 2) f[i][j] |= f[i][j - 2];
                    if(check(i, j - 1)) f[i][j] |= f[i - 1][j];
                } else{
                    if(check(i, j)) f[i][j] |= f[i - 1][j - 1];
                }
            }
        return f[ls][lp];
    }
};

11. 盛最多水的容器

思路:

双指针
很显然的一个事实是:高度取决于短的板子
我们可以逐渐缩小宽度来获得更高的高度
    
// 当h[i] < h[j]时,i++, 那么高度是有可能变大的,如果是j--,那么高度只可能更小,并且由于宽度还变小了,那么j--一定不会是最优解。
if h[i] < h[j]:
    i ++;
else j --;

代码:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int n = height.size();
        int res = 0;
        int i = 0, j = n - 1;
        while(i < j){
            int v = (j - i) * min(height[i], height[j]);
            res = max(res, v);
            if(height[i] < height[j]) i ++;
            else j --;
        }
        
        return res;
    }
};

12. 整数转罗马数字

思路:

把罗马字符可以代表的字符都手动预处理下来,共计13项,然后从大到小遍历即可。

代码:

 string rome[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};

int val[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};

class Solution {
public:
    
   
    
    string intToRoman(int num) {
        string res = "";
        for(int i = 0; i < 13; i ++){
            while(num >= val[i]){
                res += rome[i];
                num -= val[i];
            }
        }
        return res;
    }
};

13. 罗马数字转整数

思路:

用hash映射出罗马字母对应的数,然后从左往右遍历一遍,如果当前值小于左边就减,反之就加。(注意处理边界)

代码:

class Solution {
public:
    int romanToInt(string s) {
        map<char, int> mp;
        mp['I'] = 1;
        mp['V'] = 5;
        mp['X'] = 10;
        mp['L'] = 50;
        mp['C'] = 100;
        mp['D'] = 500;
        mp['M'] = 1000;
        
        int n = s.length();
        int res = 0;
        for(int i = 0; i < n - 1; i ++){
            if(mp[s[i]] >= mp[s[i + 1]])
                res += mp[s[i]];
            else res -= mp[s[i]];
        }
        res += mp[s[n - 1]];
        return res;
    }
};

14. 最长公共前缀

思路:

暴力

代码:

class Solution {
public:
    
    int min(int a, int b){
        return a <= b ? a : b;
    }
    
    string longestCommonPrefix(vector<string>& strs) {
        string res = "";
        int n = strs.size();
        if(n == 0) return "";
        int mn = 1e9;
        for(int i = 0; i < n; i ++) mn = min(mn, strs[i].size());
        for(int i = 0; i < mn; i ++){
            char c = strs[0][i];
            int mark = 1;
            for(int j = 1; j < n; j ++)
                if(strs[j][i] != c){
                    mark = 0;
                    break;
                }
            if(mark) res += c;
            else break;
        }
        return res;
    }
};

51. N 皇后

思路:

dfs枚举

代码:

class Solution {
public:
    
    bool check(int i, int pos[]){
        for(int j = 1; j < i; j ++)
            if(pos[i] == pos[j] || abs(i - j) == abs(pos[i] - pos[j])) return false;
        return true;
    }
    
    vector<string> record(int pos[], int n){
        vector<string> res;
        for(int i = 1; i <= n; i ++){
            string tmp = "";
            for(int j = 1; j <= n; j ++)
                if(pos[i] == j) tmp += 'Q';
                else tmp += '.';
            res.push_back(tmp);
        }
        return res;
    }
    
    void queen(int i, int *pos, int n, vector<vector<string>> & res){
        if(i > n) res.push_back(record(pos, n));
        else{
            for(int j = i; j <= n; j ++){
                swap(pos[i], pos[j]);
                if(check(i, pos)) queen(i + 1, pos, n, res);
                swap(pos[i], pos[j]);
            }
        }
    }
    
    vector<vector<string>> solveNQueens(int n) {
        vector<vector<string>> res;
        int pos[n + 1];
        for(int i = 1; i <= n; i ++) pos[i] = i;
        queen(1, pos, n  res);
        return res;
    }
};

216. 组合总和 III

思路:

dfs 暴力枚举

代码:

class Solution {
public:
    
    vector<vector<int>> res;
    int a, b;
    void dfs (int sum, int num, int cnt, vector<int> vec){
        if(cnt == a && sum == b){
            res.push_back(vec);
            return;
        }
        if(num > 9 || sum > b || cnt > a) return;
        for(int i = num; i <= 9; i ++){
            vec.push_back(i);
            dfs(sum + i, i + 1, cnt + 1, vec);
            vec.pop_back();
        }
    }
    
    
    vector<vector<int>> combinationSum3(int k, int n) {
        
        
        a = k, b = n;
        
        vector<int> vec;
        dfs(0, 1, 0, vec);
        return res;
        
    }
};
posted @ 2020-09-23 15:42  nonameless  阅读(140)  评论(0编辑  收藏  举报