IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> leetcode 11-20 -> 正文阅读

[数据结构与算法]leetcode 11-20

leetcode 11-20

11.盛最多水的容器

解题思路

单调栈+二分

首先可以想到一个贪心的思路:对于每个候选的右边界j,它应该匹配的左边界i是最靠左的且满足h[i]>=h[j]的那个位置(当然还有另外一种情况,左侧边界i充当最小值,这个只要把数组反一下再做一次上面的算法,更新答案就好了。)

两种情况:固定左端点,找右端点的最大值;固定右端点,找左端点的最大值,最后取max

代码

const int N = 3e4 + 10;
class Solution {
public:
    int maxArea(vector<int>& height) {
        // 固定右端点
        memset(q, -1, sizeof q);
        int res = -1, len = 0;
        for(int i = 0; i < height.size(); ++i){
            if(!len || height[i] > q[len - 1].first){
                // 如果栈中有值,那么计算当前端点作为右端点的最大值
                if(len) res = max(res, min(height[i], q[len - 1].first) * (i - q[len - 1].second));
                // 将当前值加入栈顶
                q[len++] = {height[i], i};
            }else{
                // 找到单调栈中从小到大排列中,第一个大于height[i]的数,计算其面积
                int ll = 0, rr = len - 1;
                while(ll < rr){
                    int mid = ll + rr >> 1;
                    if(q[mid].first >= height[i]) rr = mid;
                    else ll = mid + 1;
                }
                res = max(res, min(height[i], q[rr].first) * (i - q[rr].second));
            }
        }
		
        // 固定左端点,和上面很像
        memset(q, -1, sizeof q);
        len = 0;
        for(int i = height.size() - 1; i >= 0; --i){
            if(!len || height[i] > q[len - 1].first){
                // 不同处: 计算面积
                if(len) res = max(res, min(height[i], q[len - 1].first) * (i - q[len - 1].second));
                q[len ++] = {height[i], i};
            }else{
                int ll = 0, rr = len - 1;
                while(ll < rr){
                    int mid = ll + rr >> 1;
                    if(q[mid].first >= height[i]) rr = mid;
                    else ll = mid + 1;
                }
                // 不同处: 计算面积
                res = max(res, min(height[i], q[rr].first) * (q[rr].second - i));
            }
        }
        return res;
    }
private:
    pair<int, int> q[N];
};

12.整数翻转罗马数字

解题思路

查表法,当前值无非就是表中这几种情况的组合,比如 600 = 500 + 100,查表可算出

代码

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.罗马数字转整数

解题思路

除了4和9,其他的都可以通过查表然后加上对应的值,

对于4和9,我们只需要特判一下,如果下一个值大于当前的值,那么结果减去当前的值,例子:"LXIV" = 64中,L X V我们都需要加,I我们需要减

代码

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

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

14.最长公共前缀

解题思路

对比对各对应位置的字符是否相等,全相等时则进入下一个字符匹配

代码

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

        for(int i = 0;; i++){
            if(i >= strs[0].size()) return res;
            char c = strs[0][i];
            for(auto& str : strs){
                if(i >= str.size() || str[i] != c) return res;
            }
            res += c;
        }

        return res;
    }
};

15.三数之和

解题思路

三个指针:枚举最小的指针i,对于每一个i,用双指针j,k算出剩余两数之和

复杂度:O(n^2)

代码

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.最接近的三数之和

解题思路

和15题相同,用pair存最小差值和对应的和。

代码

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

17.电话号码的字母组合

解题思路

经典递归

代码

class Solution {
public:
    vector<string> ans;
    string strs[10] = {
        "", "", "abc", "def",
        "ghi", "jkl", "mno",
        "pqrs", "tuv", "wxyz"
    };

    void dfs(string& digits, int u, string path){
        if(u == digits.size()) ans.push_back(path);
        else{
            for(auto c : strs[digits[u] - '0'])
                dfs(digits, u + 1, path + c);
        }
    }
    vector<string> letterCombinations(string digits) {
        if(digits.empty()) return ans;
        dfs(digits, 0, "");
        return ans;
    }
};

18.四数之和

解题思路

参考15.三数之和,固定两个数,剩余两个数采用双指针算法。

代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        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; j < nums.size(); ++j){
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                for(int k = j + 1, l = nums.size() - 1; k < l; ++k){
                    if(k > j + 1 && nums[k] == nums[k - 1]) continue;
                    while(k < l - 1 && nums[k] + nums[l - 1] >= target - nums[i] - nums[j]){
                        --l;
                    }
                    if(nums[k] + nums[l] == target - nums[i] - nums[j] )
                        res.push_back({nums[i], nums[j], nums[k], nums[l]});
                }
            }
        }
        return res;
    }
};

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

解题思路

对于链表,如果可能改变头指针,那么就申请一个虚拟节点;

使用双指针,快指针先从dummy节点n步,然后slow指针和fast指针同时走,直到fast->next==nullptr,此时,slow->next指向的即为需要删除的节点

代码

/**
 * 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) {
        auto dummy = new ListNode(-1, head);

        auto fast = dummy;
        while(n > 0 && fast->next){
            fast = fast->next;
            n--;
        }

        auto slow = dummy;
        while(fast->next){
            fast = fast->next;
            slow = slow->next;
        }
        slow->next = slow->next->next;
        return dummy->next;
    }
};

20.有效的括号

解题思路

维持一个栈,遇到([{则入栈,其余时刻判断栈是否为空且栈顶元素是否配对;

遍历结束后判断栈是否为空,不为空,则说明有多余的括号未匹配

代码

class Solution {
public:
    bool isValid(string s) {
        stack<char> stk;
        for(int i = 0; i < s.size(); ++i){
            if(s[i] == '(' || s[i] == '[' || s[i] == '{') stk.push(s[i]);
            else if(s[i] == ')'){
                if(!stk.empty() && stk.top() == '(') stk.pop();
                else return false;
            }else if(s[i] == ']'){
                if(!stk.empty() && stk.top() == '[') stk.pop();
                else return false;
            }else{
                if(!stk.empty() && stk.top() == '{') stk.pop();
                else return false;
            }
        }
        if(stk.size()) return false;
        return true;
    }
};
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-09 10:28:44  更:2021-08-09 10:29:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:30:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码