Leetcode11~20题整理

11. 盛最多水的容器

比较暴力的做法:

class Solution {
public:
    int maxArea(vector<int>& h) {
        vector<int> t;
        int n = h.size();
        int res = -1;
        for(int i = 0; i < n; i++) {
            for(int j = 0; j < (int)t.size(); j++) {
                res = max(res, (i - t[j]) * min(h[i], h[t[j]]));
            }
            if(!t.size() || h[i] > h[t.back()]) t.push_back(i);
        }

        return res;
    }
};

正解,双指针

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

12. 整数转罗马数字

找规律,将几个特殊的表示存下来,

比如num = 1254, res = ""

1254 ≥ 1000,则num = 1254 - 1000 = 254, res = "M"

254 ≥ 100, num = 254 - 100 = 154, res = "MC"

154 ≥ 100, num = 154 - 100 = 54, res = "MCC"

54 ≥ 50. num = 54 - 50 = 4, res = "MCCL"

4 ≥ 4, num = 4 - 4 = 0, res = "MCCLIV"

class Solution {
public:
    string intToRoman(int num) {
        int values[] = {
            1000,
            900, 500, 400, 100,
            90, 50, 40, 10,
            9, 5, 4, 1
        };
        string reps[] = {
            "M",
            "CM", "D", "CD", "C",
            "XC", "L", "XL", "X",
            "IX", "V", "IV", "I"
        };
        
        string res = "";
        for(int i = 0; i < 13; i++) {
            while(num >= values[i]) {
                num -= values[i];
                res += reps[i];
            }
        }

        return res;
    }
};

13. 罗马数字转整数

特殊情况是下面几个,其他的都是直接将字符表示的阿拉伯数字相加,所以遇到一个字符表示的阿拉伯数字比后面字符的阿拉伯数字要小的话说明就是下面这种情况

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。 
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。

class Solution {
public:
    int romanToInt(string s) {
        unordered_map<char, int> hs;
        hs['I'] = 1, hs['V'] = 5;
        hs['X'] = 10, hs['L'] = 50,
        hs['C'] = 100, hs['D'] = 500,
        hs['M'] = 1000;

        int res = 0;
        for(int i = 0; i < s.size(); i++) {
            if(i + 1 < s.size() && hs[s[i]] < hs[s[i + 1]]) {
                res -= hs[s[i]];
            }else {
                res += hs[s[i]];
            }
        }

        return res;
    }
};

14. 最长公共前缀

以第一个字符串为基准,不断增加公共前缀的长度,直到strs中有任何一个字符串不满足即退出

方法一:

会造成很多冗余匹配,复杂度较高

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }
        string prefix = strs[0];
        int count = strs.size();
        for (int i = 1; i < count; ++i) {
            prefix = longestCommonPrefix(prefix, strs[i]);
            if (!prefix.size()) {
                break;
            }
        }
        return prefix;
    }

    string longestCommonPrefix(const string& str1, const string& str2) {
        int length = min(str1.size(), str2.size());
        int index = 0;
        while (index < length && str1[index] == str2[index]) {
            ++index;
        }
        return str1.substr(0, index);
    }
};

方法二:

最多遍历所有字符串的字符个数之和

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string res = "";
        if(strs.size() == 0) return res;

        for(int i = 0; ; i++){
            if(i >= strs[0].size()) return res;
            char ch = strs[0][i];
            for(int j = 1; j < strs.size(); j++) {
                if(i >= strs[j].size() || strs[j][i] != ch) {
                    return res;
                }
            }
            res += ch;
        }

        return res;
    }
};

15. 三数之和

为了避免重复,我们保证三个数对以不降序排列,所有需要先将整个数组排序

枚举第一个数字然后转换成两数之和的问题,这里的两数之和要求找到所有满足条件的而不是像第一题那样只用找一个,所以要用双指针算法来找,具体如下:

sum = nums[i] + nums[j]

  • sum > tar,则i往左走,令sum变小
  • sum < tar,则j往右走,令sum变大
  • sum == tar,则表示找到了一对,此时i往右走,j往左走,在此期间为了枚举重复,需要在指针移动的时候判重
class Solution {
public:
    vector<vector<int>> twoSum(vector<int>& nums, int l, int r, int tar, int x) {
        vector<vector<int>> res;
        for(int i = l, j = r; i < j;) {
            if(nums[i] + nums[j] < tar) {
                i++;
            }else if(nums[i] + nums[j] > tar) {
                j--;
            }else {
                res.push_back({x, nums[i], nums[j]});
                while(i < j && nums[i] == nums[i + 1]) i++;
                while(i < j && nums[j] == nums[j - 1]) j--;
                i++, j--;
            }
        }
        return res;
    }
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        for(int i = 0; i < n; i++) {
            if(i && nums[i] == nums[i - 1]) continue;
            auto t = twoSum(nums, i + 1, n - 1, -nums[i], nums[i]);
            res.insert(res.end(), t.begin(), t.end());
        }

        return res;
    }
};

试探性的减:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());
        for(int i = 0; i < nums.size(); i++) {
            if(i && nums[i] == nums[i - 1]) continue;
            for(int j = i + 1, k = nums.size() - 1; j < k; j++) {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                while(j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= 0) k-- ;
                if(nums[i] + nums[j] + nums[k] == 0) {
                    res.push_back({nums[i], nums[j], nums[k]});
                }
            }
        }

        return res;
    }
};

16. 最接近的三数之和

和上一题差不多,只不过是需要找到大于等于target最小的三数和以及小于等于target最大的三数和,然后两个差值的绝对值取最小值对应的和就是答案

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        pair<int, int> res(INT_MAX, INT_MAX);
        for(int i = 0; i < n; i++) {
            if(i && nums[i] == nums[i - 1]) continue;
            for(int j = i + 1, k = n - 1; j < k; j++) {
                while(j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= target) k--;
                int sum = nums[i] + nums[j] + nums[k];
                res = min(res, {abs(sum - target), sum});

                if(k - 1 > j) {
                    sum = nums[i] + nums[j] + nums[k - 1];
                    res = min(res, {target - sum, sum});
                }
            }
        }
        return res.second;
    }
};

17. 电话号码的字母组合

dfs爆搜

class Solution {
public:
    string hs[11] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    vector<string> res;
    void dfs(int u, string s, string digits) {
        if(u == digits.size()) {
            if(s != "")
                res.push_back(s);
            return ;
        }
        int idx = digits[u] - '0';
        for(auto c : hs[idx]) {
            s = s + c;
            dfs(u + 1, s, digits);
            s.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {

        dfs(0, "", digits);

        return res;
    }
};

18. 四数之和

和三数之和一样,只不过是枚举i和j,然后k和u使用双指针算法

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<vector<int>> res;
        for(int i = 0; i < n; i++) {
            if(i && nums[i] == nums[i - 1]) continue;
            for(int j = i + 1; j < n; j++) {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                for(int k = j + 1, u = n - 1; k < u; k++) {
                    if(k > j + 1 && nums[k] == nums[k - 1]) continue;
                    while(k < u - 1 && 1ll * nums[i] + nums[j] + nums[k] + nums[u - 1] >= target) u--;
                    if(1ll * nums[i] + nums[j] + nums[k] + nums[u] == target) {
                        res.push_back({nums[i], nums[j], nums[k], nums[u]});
                    }
                }
            }
        }

        return res;
    }
};

19. 删除链表的倒数第 N 个结点

方法一:

先对链表进行一次遍历,得到节点总数,然后遍历倒数第n+1个点(因为删除时需要知道前面一个点),也就是从前往后第tot - n 个点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        int tot = 0;
        ListNode* p = dummy->next;
        while(p) {
            tot++;
            p = p->next;
        }
        int cur = 0;
        p = dummy;
        while(cur < (tot - n)) {
            p = p->next;
            cur++;
        }
        p->next = p->next->next;

        return dummy->next;
    }
  };

方法二:

快慢指针

设置两个指针p1p2,让快指针p1先走 n步,然后两个指针再同时走。当第二个指针走到最后时,第一个指针的位置就是需要被删除的节点。

由于我们设置了虚拟头节点dummy,所以当开始p1p2都在dummy时,p1n步,然后同时走,最后p2停止的位置就是倒数第n+1个节点

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* dummy = new ListNode(-1);
        dummy->next = head;
        ListNode* p1 = dummy;
        ListNode* p2 = dummy;
        while(n--) p1 = p1->next;
        while(p1->next) {
            p1 = p1->next;
            p2 = p2->next;
        }
        p2->next = p2->next->next;
        
        return dummy->next;
    }
};

20. 有效的括号

维护一个栈,如果是左括号就将其入栈, 如果是右括号就拿栈顶元素出来看是否匹配

class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        for(auto c : s) {
            if(c == '(' || c == '[' || c == '{') stk.push(c);
            else {
                if(stk.size()) {
                    char top = stk.top();
                    if((c == ')' && top == '(')  || (c == '}' && top == '{') || (c == ']' && top == '[')) {
                        stk.pop();
                    }else {
                        return false;
                    }
                }else {
                    return false;
                }
            }
        }
        if(stk.size()) return false;
        else return true;
    }
};
posted @ 2023-05-07 15:13  junlin623  阅读(18)  评论(0编辑  收藏  举报