LeetCode刷题记11-20

LeetCode 11. 盛最多水的容器

题目链接

https://www.acwing.com/solution/content/100/

思路

双指针问题 比较简单

AC代码1

class Solution {
public:
    int maxArea(vector<int>& height) &#123;
        // 双指针
        int res = 0;
        for (int i = 0, j = height.size() - 1; i < j;)
        &#123;
            // 短板效应
            res = max(res, min(height[i], height[j]) * (j - i));
            // 如果左边高度比右边高的话 移动右边 反之亦然
            if(height[i] > height[j]) j --;
            else i ++;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 12. 整数转罗马数字

题目链接

https://leetcode.cn/problems/integer-to-roman/

思路

y总总结的规律, 权值表

M CM D CD C XC L XL X IX V IV I
1000 900 500 400 100 90 50 40 10 9 5 4 1

https://www.acwing.com/solution/content/101/

AC代码1

class Solution &#123;
public:
    string intToRoman(int num) &#123;
        int values[] = &#123;
            1000,
            900, 500, 400, 100,
            90, 50, 40, 10,
            9, 5, 4, 1
        &#125;;
        string reps[] = &#123;
            "M",
            "CM", "D", "CD", "C",
            "XC", "L", "XL", "X",
            "IX", "V", "IV", "I"
        &#125;;
        string res;
        // 遍历所有权值 类似于二进制
        for (int i = 0; i < 13; i ++)
        &#123;
            while (num >= values[i])
            &#123;
                num -= values[i];
                res += reps[i];
            &#125;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 13. 罗马数字转整数

题目链接

https://leetcode.cn/problems/roman-to-integer/

思路

这题是上一道题的反转,难度比上一题低一点,找好规律只需要注意点,只要该字符比下一个字符权值小,则减去该字符对应的权值即可,该题也是直接一遍就AC

AC代码1

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

        for (int i = 0; i < s.size(); i ++)
        &#123;
            if (i + 1 < s.size() && hash[s[i]] < hash[s[i + 1]])
            &#123;
                res -= hash[s[i]];
            &#125;
            else
            &#123;
                res += hash[s[i]];
            &#125;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 14. 最长公共前缀

题目链接

https://leetcode.cn/problems/longest-common-prefix

思路

枚举每个字符串 对比每个字符即可

AC代码1

class Solution &#123;
public:
    string longestCommonPrefix(vector<string>& strs) &#123;
        string res;
        if (strs.empty()) return res;

        // 从第一个字符开始枚举
        for (int i = 0; ; i ++)
        &#123;
            if(i >= strs[0].size()) return res;
            char c = strs[0][i];
            for (auto& str : strs)
            &#123;
                if (i >= str.size() || str[i] != c)
                    return res;
            &#125;
            res += c;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 15. 三数之和

题目链接

https://leetcode.cn/problems/3sum/

思路

排序 + 双指针

  1. 先对数组排序
  2. 对于有序数组nums 固定好i, j = i + 1 ,k = nums.size()对(j , k)双指针查找
  3. 此时只有当nums[i] + nums[j] + nums [k - 1] >= 0 才能往左边移动k,直到j == k为止
  4. 后面继续移动i,j设置为 i + 1

AC代码1

class Solution &#123;
public:
    vector<vector<int>> threeSum(vector<int>& nums) &#123;
        vector<vector<int>> res;
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i ++)
        &#123;
            if (i && nums[i] == nums[i - 1]) continue;
            // 双指针
            for (int j = i + 1, k = nums.size() - 1; j < k; j ++)
            &#123;
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                //不符合情况的时候向左移动k
                //该序列有序 k左移三个数总和会变小 所以只需判断当前三个数之和是否是大于0即可
                while (j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= 0) k --;
                if (nums[i] + nums[j] + nums[k] == 0)
                &#123;
                    res.push_back(&#123;nums[i], nums[j], nums[k]&#125;);
                &#125;
            &#125;
        &#125;
        return res;
    &#125;
&#125;;

LeetCode 16. 最接近的三数之和

题目链接

https://leetcode.cn/problems/3sum-closest

思路

跟上一题类似 注意一下target左边小和右边大的这两个总和即可

AC代码1

class Solution &#123;
public:
    int threeSumClosest(vector<int>& nums, int target) &#123;
        sort(nums.begin(), nums.end());
        pair<int, int> res(INT_MAX, INT_MAX); 
        for (int i = 0; i < nums.size(); i ++)
        &#123;
            for (int j = i + 1, k = nums.size() - 1; j < k; j ++)
            &#123;
                while (j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= target) k --;
                int s = nums[i] + nums[j] + nums[k];
                // 找到总和最接近target
                res = min(res, make_pair(abs(s - target), s));
                // 前面考虑了在target右边的情况 下面考虑在target左边的情况
                if (j < k - 1)
                &#123;
                    int s = nums[i] + nums[j] + nums[k - 1];
                    res = min(res, make_pair(abs(s - target), s));
                &#125;
            &#125;
        &#125;
        return res.second;
    &#125;
&#125;;

LeetCode 17. 电话号码的字母组合

题目链接

https://leetcode.cn/problems/letter-combinations-of-a-phone-number/

思路

参考以下题解
https://www.acwing.com/solution/content/15003/

AC代码1

class Solution &#123;
public:
    vector<string> ans;
    string strs[10] = &#123;
        "", "", "abc", "def",
        "ghi", "jkl", "mno",
        "pqrs", "tuv", "wxyz" 
    &#125;;
    void dfs(string& digits, int u, string path)
    &#123;
        if (u == digits.size()) 
        &#123;
            ans.push_back(path);
        &#125;
        else 
        &#123;
            for (auto c : strs[digits[u] - '0'])
            &#123;
                dfs(digits, u + 1, path + c);
            &#125;
        &#125;

    &#125;
    vector<string> letterCombinations(string digits) &#123;
        if (digits == "")
            return ans;
        dfs(digits, 0, "");
        return ans;
    &#125;
&#125;;

LeetCode 18. 四数之和

题目链接

https://leetcode.cn/problems/4sum

思路

跟15题三数之和差不多,看前面的LeetCode 15的题解就好了,固定好i j,后面用双指针

AC代码1

class Solution &#123;
public:
    typedef long long LL;
    vector<vector<int>> fourSum(vector<int>& nums, int target) &#123;
        vector<vector<int>> res;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        for (int i = 0; i < n; i ++)
        &#123;
            if (i && nums[i] == nums[i - 1]) continue;
            for (int j = i + 1; j < n; j ++)
            &#123;
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                for (int l = j + 1, r = n - 1; l < r; l ++)
                &#123;
                    if (l > j + 1 && nums[l] == nums[l - 1]) continue;
                    while(l < r - 1 && (LL)nums[i] + nums[j] + nums[l] + nums[r - 1] >= target) r --;
                    if ((LL)nums[i] + nums[j] + nums[l] + nums[r] == target)
                    &#123;
                        res.push_back(&#123;nums[i], nums[j], nums[l], nums[r]&#125;);
                    &#125;
                &#125;
            &#125;
        &#125;
        return res;
    &#125;
&#125;;

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

题目链接

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

思路

注意加个头结点防止只有一个元素,而要删除该元素
方法一:数学方法

  1. p指向头结点
    1. 让p走k - n - 1步即可到达删除结点的前驱,其中k为链表长度

方法二:双指针(时间更快)

  1. 都指向头结点
    1. q走n + 1步
    2. p q同时走 当q到达尾部NULL时候,p指向倒数第n个数的前驱

AC代码1

方法一:
/**
 * Definition for singly-linked list.
 * struct ListNode &#123;
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) &#123;&#125;
 *     ListNode(int x) : val(x), next(nullptr) &#123;&#125;
 *     ListNode(int x, ListNode *next) : val(x), next(next) &#123;&#125;
 * &#125;;
 */
class Solution &#123;
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) &#123;
        ListNode* dummy_head = new ListNode(-1);
        dummy_head->next = head;

        int k = 0;
        auto p = dummy_head;
        while(p->next)
        &#123;
            k ++;
            p = p->next;
        &#125;
        auto q = dummy_head;
        for (int i = 0; i < k - n; i ++) q = q->next;
        q->next = q->next->next;
        return dummy_head->next;
    &#125;
&#125;;

AC代码2

方法二:时间更快

/**
 * Definition for singly-linked list.
 * struct ListNode &#123;
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) &#123;&#125;
 *     ListNode(int x) : val(x), next(nullptr) &#123;&#125;
 *     ListNode(int x, ListNode *next) : val(x), next(next) &#123;&#125;
 * &#125;;
 */
class Solution &#123;
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) &#123;
        ListNode* dummy_head = new ListNode(-1);
        dummy_head->next = head;

        ListNode* p = dummy_head;
        ListNode* q = dummy_head;

        // 先让q走n + 1步 因为前面有虚拟结点
        for (int i = 0; i < n + 1; i ++) q = q->next;

        while (q)
        &#123;
            p = p->next;
            q = q->next;
        &#125;
        p->next = p->next->next;
        return dummy_head->next;
    &#125;
&#125;;

LeetCode 20. 有效的括号

题目链接

https://leetcode.cn/problems/valid-parentheses/

思路

方法一:

  1. 使用栈存储,遇到( { [ 压入栈
  2. 遇到) } ] 查看栈顶是否匹配
  3. 结束查看栈是否为空

方法二:

  1. 使用ascii值

AC代码1

// 方法一:
class Solution &#123;
public:
    bool isValid(string s) &#123;
        stack<int> stk;

        for (int i = 0; i < s.size(); i ++)
        &#123;
            if (s[i] == '(' || s[i] == '&#123;' || s[i] == '[')
            &#123;
                stk.push(s[i]);
            &#125;
            else if (s[i] == ')')
            &#123;
                if (stk.empty() || stk.top() != '(') return false;
                stk.pop();
            &#125;
            else if (s[i] == '&#125;')
            &#123;
                if(stk.empty() || stk.top() != '&#123;') return false;
                stk.pop();
            &#125;
            else if (s[i] == ']')
            &#123;
                if(stk.empty() || stk.top() != '[') return false;
                stk.pop();
            &#125;
        &#125;
        return stk.empty();
    &#125;
&#125;;

AC代码2

// 方法二:
class Solution &#123;
public:
    bool isValid(string s) &#123;
        stack<int> stk;

        for (auto c : s)
        &#123;
            if (c == '(' || c == '&#123;' || c == '[')
            &#123;
                stk.push(c);
            &#125;
            else
            &#123;
                if (!stk.empty() && abs(stk.top() - c) <= 2) stk.pop();
                else return false;
            &#125;
        &#125;
        return stk.empty();
    &#125;
&#125;;

  转载请注明: Justin博客 LeetCode刷题记11-20

 上一篇
【算法基础篇】DFS和BFS及其经典习题 【算法基础篇】DFS和BFS及其经典习题
DFS深搜深搜解决排列问题,也是一个很好的模板 问题给定一个整数 n,将数字 1∼n 排成一排,将会有很多种排列方法。 AC#include <iostream> using namespace std; const int N =
下一篇 
LeetCode刷题记1-10 LeetCode刷题记1-10
前言今年准备考研想固定好每周刷10道算法题以上,特地开这个栏目来记录刷题过程,按序号来刷,每10题一篇文章 LeetCode 1. 两数之和题目链接 https://leetcode.cn/problems/two-sum/ 思路1 暴力
  目录