《LeetCode 顺序刷题》11 -20

11、[中等] 盛最多水的容器

双指针

c++
复制代码
class Solution {
public:
    int maxArea(vector<int>& height) {
        int left = 0;
        int right = height.size() - 1;
        int ret = 0;
        while (left < right) {
            int v = min(height[left], height[right]) * (right - left);
            ret = max(ret, v);

            // 移动指针
            if (height[left] < height[right]) {
                ++left;
            } else {
                --right;
            }
        }
        return ret;
    }
};
Java
java 复制代码
class Solution {
    public int maxArea(int[] height) {
        int left = 0; // 左指针
        int right = height.length - 1; // 右指针
        int maxArea = 0; // 最大面积

        while (left < right) {
            // 计算当前容器的面积
            int currentArea = Math.min(height[left], height[right]) * (right - left);
            // 更新最大面积
            maxArea = Math.max(maxArea, currentArea);

            // 移动指针
            if (height[left] < height[right]) {
                left++; // 如果左边高度较小,移动左指针
            } else {
                right--; // 如果右边的高度较小,移动右指针
            }
        }

        return maxArea;
    }
}

12、[中等] 整数转罗马数字

数学 字符串

模拟

复制代码
const pair<int, string> valueSymbols[] = {
    {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"},
    {90, "XC"},  {50, "L"},   {40, "XL"}, {10, "X"},   {9, "IX"},
    {5, "V"},    {4, "IV"},   {1, "I"},
};

class Solution {
public:
    string intToRoman(int num) {
        string roman;
        for (const auto& [value, symbol] : valueSymbols) {
            while (num >= value) {
                num -= value;
                roman += symbol;
            }
            if (num == 0) {
                break;
            }
        }
        return roman;
    }
};

硬编码数字

复制代码
const string thousands[] = {"", "M", "MM", "MMM"};
const string hundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
const string tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
const string ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};

class Solution {
public:
    string intToRoman(int num) {
        return thousands[num / 1000] + hundreds[num % 1000 / 100] + tens[num % 100 / 10] + ones[num % 10];
    }
};

13、[简单] 罗马数字转整数

哈希表 数学 字符串

复制代码
class Solution {
private:
    unordered_map<char, int> symbolValue = {{'I', 1},   {'V', 5},   {'X', 10}, {'L', 50},  {'C', 100}, {'D', 500}, {'M', 1000}};

public:
    int romanToInt(string s) {
        int ret = 0;
        int n = s.size();
        for (int i = 0; i < n; ++i) {
            int value = symbolValue[s[i]];
            if (i < n - 1 && value < symbolValue[s[i + 1]]) {
                ret -= value;
            } else {
                ret += value;
            }
        }
        return ret;
    }
};

14、[简单] 最长公共前缀

字符串 二分查找

横向扫描

复制代码
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        // 解法一:两两比较
        string ret = strs[0];
        for (int i = 1; i < strs.size(); i++) {
            ret = findCommon(ret, strs[i]);
        }
        return ret;
    }

    string findCommon(string& s1, string& s2)
    {
        int i = 0;
        while (i < min(s1.size(), s2.size()) && s1[i] == s2[i]) {
            i++;
        }
        return s1.substr(0, i);
    }
};

纵向扫描

复制代码
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        }

        int length = strs[0].size();
        int count = strs.size();
        for (int i = 0; i < length; i++) {
            char c = strs[0][i];
            for (int j = 1; j < count; j++) {
                if (i == strs[j].size() || strs[j][i] != c) {
                    return strs[0].substr(0, i);
                }
            }
        }

        return strs[0];
    }
};

分治

复制代码
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (!strs.size()) {
            return "";
        } else {
            return longestCommonPrefix(strs, 0, strs.size() - 1);
        }
    }

    string longestCommonPrefix(const vector<string>& strs, int start, int end) {
        if (start == end) {
            return strs[start];
        } else {
            int mid = (start + end) / 2;
            string lcpLeft = longestCommonPrefix(strs, start, mid);
            string lcpRight = longestCommonPrefix(strs, mid + 1, end);
            return commonPrefix(lcpLeft, lcpRight);
        }
    }

    string commonPrefix(const string& lcpLeft, const string& lcpRight) {
        int minLength = min(lcpLeft.size(), lcpRight.size());
        for (int i = 0; i < minLength; i++) {
            if (lcpLeft[i] != lcpRight[i]) {
                return lcpLeft.substr(0, i);
            }
        }
        return lcpLeft.substr(0, minLength);
    }
};

排序

复制代码
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if (strs.empty()) {
            return "";
        }

        sort(strs.begin(), strs.end());
        string start = strs.front();
        string end = strs.back();
        int n = min(start.size(), end.size());
        int i = 0;
        for (i = 0; i < n && start[i] == end[i]; i++)
            ;

        return string(start, 0, i);
    }
};

15、[中等] 三数之和

排序 数组 双指针

复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ret;

        int n = nums.size();
        for (int i = 0; i < n; ++i) {
            if (nums[i] > 0) {
                break;
            }
            int left = i + 1;
            int right = n - 1;
            int target = -nums[i];

            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum > target) {
                    --right;
                } else if (sum < target) {
                    ++left;
                } else {
                    ret.push_back({nums[i], nums[left], nums[right]});
                    ++left;
                    --right;

                    while (left < right && nums[left] == nums[left - 1]) {
                        ++left;
                    }
                    while(left < right && nums[right] == nums[right + 1]) {
                        --right;
                    }
                }
            }

            while (i < n - 1 && nums[i] == nums[i + 1]) {
                ++i;
            }
        }

        return ret;
    }
};

16、[中等] 最接近的三数之和

排序 数组 双指针

复制代码
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int n = nums.size();
        int ret = 1e7;

        // 根据差值的绝对值来更新答案
        auto update = [&](int cur) {
            if (abs(cur - target) < abs(ret - target)) {
                ret = cur;
            }
        };

        // 枚举 a
        for (int i = 0; i < nums.size(); i++) {
            // 保证和上一次枚举的元素不相等
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            // 使用双指针枚举 b 和 c
            int left = i + 1, right = n - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                // 如果和为 target 直接返回答案
                if (sum == target) {
                    return target;
                }

                update(sum);
                if (sum > target) {
                    // 如果和大于 target,移动 c 对应的指针
                    right--;
                    while (left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }

                } else {
                    // 如果和小于 target,移动 b 对应的指针
                    left++;
                    while (left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
                }
            }
        }

        return ret;
    }
};

17、[中等] 电话号码的字母组合

哈希表 字符串 回溯

复制代码
class Solution {
private:
    string hash[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    string path;
    vector<string> ret;

    void dfs(string& digits, int pos) {
        if (pos == digits.size()) {
            ret.push_back(path);
            return;
        }
        for (const auto& ch : hash[digits[pos] - '0']) {
            path.push_back(ch);
            dfs(digits, pos + 1);
            path.pop_back();
        }
    }

public:
    vector<string> letterCombinations(string digits) {
        if (digits.empty()) {
            return {};
        }
        dfs(digits, 0);
        return ret;
    }
};

18、[中等] 四数之和

排序 数组 双指针

复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int n = nums.size();
        if (n < 4) {
            return {};
        }
        vector<vector<int>> ret;
        sort(nums.begin(), nums.end());

        for (int i = 0; i < n - 3; i++) {
            for (int j = i + 1; j < n - 2; j++) {
                long long newtarget = (long long)target - nums[i] - nums[j];
                int left = j + 1, right = n - 1;
                while (left < right) {
                    int sum = nums[left] + nums[right];
                    if (sum > newtarget) {
                        right--;
                    } else if (sum < newtarget) {
                        left++;
                    } else {
                        ret.push_back({nums[i], nums[j], nums[left++], nums[right--]});

                        // 去重
                        while (left < right && nums[left] == nums[left - 1]) {
                            left++;
                        }
                        while (left < right && nums[right] == nums[right + 1]) {
                            right--;
                        }
                    }
                }

                while (j < n - 2 && nums[j] == nums[j + 1]) {
                    j++;
                }
            }

            while (i < n - 3 && nums[i] == nums[i + 1]) {
                i++;
            }
        }

        return ret;
    }
};

19、[中等] 删除链表的倒数第 N 个节点

链表 双指针

计算链表的长度

复制代码
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newhead = new ListNode(0, head);
        int count = 0;
        ListNode* cur = head;
        while (cur) {
            cur = cur->next;
            count++;
        }

        int gap = count - n;
        cur = newhead;
        while (gap--)
            cur = cur->next;
        ListNode* del = cur->next;
        cur->next = del->next;
        cur = newhead->next;

        delete del;
        delete newhead;
        return cur;
    }
};

复制代码
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newhead = new ListNode(0, head);
        stack<ListNode*> s;
        ListNode* cur = newhead;
        while (cur) {
            s.push(cur);
            cur = cur->next;
        }
        for (int i = 0; i < n; ++i) {
            s.pop();
        }
        ListNode* prev = s.top();
        ListNode* del = prev->next;
        prev->next = del->next;
        cur = newhead->next;
        delete del;
        delete newhead;
        return cur;
    }
};

双指针

复制代码
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode newhead;
        newhead.next = head;
        ListNode* slow = &newhead;
        ListNode* fast = &newhead;
        while (n--) {
            fast = fast->next;
        }
        while (fast->next) {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* del = slow->next;
        slow->next = del->next;
        delete del;
        return newhead.next;
    }
};

20、[简单] 有效的括号

哈希表 字符串

复制代码
class Solution {
public:
    bool isValid(string s) {
        int n = s.size();
        stack<char> st;

        for (int i = 0; i < n; i++) {
            if (s[i] == '(' || s[i] == '{' || s[i] == '[')
                st.push(s[i]);
            else if (s[i] == ')' && !st.empty() && st.top() == '(')
                st.pop();
            else if (s[i] == '}' && !st.empty() && st.top() == '{')
                st.pop();
            else if (s[i] == ']' && !st.empty() && st.top() == '[')
                st.pop();
            else
                return false;
        }

        return st.empty() == true;
    }
};

class Solution {
public:
    bool isValid(string s) {
        int n = s.size();
        if (n % 2 == 1)
            return false;

        unordered_map<char, char> pairs = {{')', '('}, {']', '['}, {'}', '{'}};
        stack<char> stk;
        for (const char& ch : s) {
            if (pairs.count(ch)) {
                if (stk.empty() || stk.top() != pairs[ch])
                    return false;
                stk.pop();
            } else
                stk.push(ch);
        }

        return stk.empty();
    }
};
相关推荐
wuqingshun3141592 小时前
说一下java的四种引用
java·开发语言
青春:一叶知秋2 小时前
【Redis存储】Redis客户端
java·数据库·redis
Jelena157795857922 小时前
淘宝图搜API接口技术深度解析:从架构设计到工程实践
python·api
乌萨奇也要立志学C++2 小时前
【洛谷】从记忆化搜索到动态规划 状态表示 + 转移方程 + 空间优化全攻略
算法·动态规划
curry____3032 小时前
c++位运算符笔记
java·c++·笔记
Hx_Ma163 小时前
测试题(一)
java
枫叶丹43 小时前
【Qt开发】Qt界面优化(四)-> Qt样式表(QSS) 选择器概况
c语言·开发语言·c++·qt
w***29853 小时前
Knife4j文档请求异常(基于SpringBoot3,查找原因并解决)
java·服务器·数据库
Bear on Toilet3 小时前
递归_二叉树_48 . 二叉树最近公共祖先查找
数据结构·算法·二叉树·dfs