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 21~30 -> 正文阅读

[数据结构与算法]leetcode 21~30

lc 21~30

21. 合并两个有序链表

单链表

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        auto dummy = new ListNode(-1), head = dummy;
        while(list1 || list2){
            int x = list1 != nullptr? list1->val : INT_MAX;
            int y = list2 != nullptr? list2->val : INT_MAX;
            if(x <= y)
                head = head->next = list1, list1 = list1->next;
            else
                head = head->next = list2, list2 = list2->next;
            //只要有哪个数为INF就说明其中一个链表已经全部加入了
            //因此刚才直接连接上剩下的一个链表,就可以结束了
            if(x == INT_MAX || y == INT_MAX)    break;
        }
        return dummy->next;
    }
};

22. 括号生成

DFS

class Solution {
public:
    vector<string> ans;
    vector<string> generateParenthesis(int n) {
        //首先明确有效括号性质:任意前缀左括号数目大于等于右括号数目
        //最终的字符串左括号数等于右括号数都为n
        dfs("", 0, 0, n);
        return ans;
    }

    void dfs(string temp, int lc, int rc, int n){
        if(lc == n && rc == n){
            ans.push_back(temp);
            return;
        }
        if(lc < n) dfs(temp + '(', lc + 1, rc, n);
        if(rc < n && lc > rc) dfs(temp + ')', lc, rc + 1, n);
    }
};

23. 合并K个升序链表

1.暴力遍历就完事了,584ms,O(n * k),n为总节点数,k为链表个数

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto dummy = new ListNode(-1), head = dummy;
        int len = lists.size();
        while(1){
            int minValm = INT_MAX, seq = 0;//记录最小的节点值,序号
            for(int i = 0; i < len; i++){
                if(lists[i] && lists[i]->val < minValm){
                    minValm = lists[i]->val;
                    seq = i;
                }
            }
            //说明所以链表都遍历完了
            if(minValm == INT_MAX) break;
            head = head->next = lists[seq];
            lists[seq] = lists[seq]->next;
        }
        return dummy->next;
    }
};

2.优先队列, O(n * logk)

class Solution {
public:
    struct Cmp{
        //优先队列与sort排序是相反的
        bool operator()(ListNode* x, ListNode* y){
            return x->val > y ->val;//升序
        }
    };

    ListNode* mergeKLists(vector<ListNode*>& lists) {
        auto dummy = new ListNode(-1), tail = dummy;
        //优先队列,底层为堆,会自动将里面的元素按规则排序,这里堆顶永远为最小值
        priority_queue<ListNode*, vector<ListNode*>, Cmp> heap;
        for(auto node : lists)
            if(node) heap.push(node);
        while(heap.size()){
            auto temp = heap.top();
            heap.pop();
            tail = tail->next = temp;
            if(temp->next) heap.push(temp->next);
        }
        return dummy->next;
    }
};

24. 两两交换链表中的节点

单链表,三点记录更新,迭代

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        //长度0或1直接返回就行
        if(!head || !head->next) return head;
        auto dummy = new ListNode(-1);//虚拟头节点大法,因为交换后head就不是新的头节点了
        dummy->next = head;
        auto pre = dummy, cur = head, ne = head->next;
        while(cur && ne){
            cur->next = ne->next;
            ne->next = cur;
            pre->next = ne;
            pre = cur;
            cur = cur->next;
            //如果新的cur节点非空,才能更新ne
            if(cur) ne = cur->next;
        }
        return dummy->next;
    }
};

y总的代码

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        for(auto p = dummy; p->next && p->next->next;){
            auto a = p->next, b = a->next;
            p->next = b;
            a->next = b->next;
            b->next = a;
            p = a;
        }
        return dummy->next;
    }
};

25. K 个一组翻转链表

单链表,k反转

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        auto dummy = new ListNode(-1);
        dummy->next = head;
        for(auto p = dummy;;){
            auto pp = p;
            //检查p后面是否有k个节点
            for(int i = 0; i < k && pp; i++) pp = pp->next;
            if(!pp) break;//没有k个
            //先将后面的k个节点内部进行指向反转(k-1次)
            auto a = p->next, b = a->next;//双指针
            for(int j = 0; j < k - 1; j++){
                auto c = b->next;
                b->next = a;
                a = b, b = c;
            }
            pp = p->next;
            pp->next = b;
            p->next = a;
            p = pp;
        }
        return dummy->next;
    }
};

26. 删除有序数组中的重复

双指针

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int len = nums.size();
        int j = 0;
        for(int i = 0; i < len; i++){
            if(!i || nums[i] != nums[i - 1])
                nums[j++] = nums[i];
        }
        return j;
    }
};

27. 移除元素

双指针,简单

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int index = 0, len = nums.size();
        for(int i = 0; i < len; i++)
            if(nums[i] != val)
                nums[index++] = nums[i];
        return index;
    }
};

28. 实现 strStr()

KMP模板

class Solution {
public:
    int strStr(string haystack, string needle) {
        //如果s的长度小于p,必不可能匹配上(如果没有这个,当needle空时就出错了)
        //现在力扣长度都改为1~10^4,这样就不会出现y总做的时候那个情况了
        if(haystack.length() < needle.length()) return -1;
        int len1 = haystack.length(), len2 = needle.length();
        string s = ' ' + haystack, p = ' ' + needle;
        vector<int> ne(len2 + 1);//c++普通数组不让用非常数的值创建大小
        //求next
        next(ne, p);
        //匹配,从1开始
        for(int i = 1, j = 0; i <= len1; i++){
            while(j && s[i] != p[j + 1]) j = ne[j];
            if(s[i] == p[j + 1]) j++;
            if(j == len2) return i - j;
        }
        return -1;
    }

    void next(vector<int>& ne, string p){
        int len = p.length() - 1, j = 0;
        //从2开始,因为j + 1与 i匹配,所以i从2开始
        for(int i = 2; i <= len; i++){
            while(j && p[i] != p[j + 1]) j = ne[j];
            if(p[i] == p[j + 1]) j++;
            ne[i] = j;
        }
    }
};

29. 两数相除

二进制位

class Solution {
public:
    int divide(int dividend, int divisor) {
        //二进制位思想,要注意溢出,(-2^31 / -1 = 2^31 溢出)
        //将两个数都取下绝对值,并记录商的符号
        typedef long long LL;
        bool is_minus = false;
        if((dividend < 0 && divisor > 0) || (dividend > 0 && divisor < 0))
            is_minus = true;
        //转LL,防止上面那样溢出
        LL a = abs((LL)dividend), b = abs((LL)divisor), res = 0;
        vector<LL> exp;
        for(LL c = b; c <= a; c += c) exp.push_back(c);
        for(int i = exp.size() - 1; i >= 0; i--){
            if(a >= exp[i]){
                a -= exp[i];
                //这里一定要让1是LL,左移31位就会造成溢出int,如 -2147483648 -1
                res += 1LL << i;
            }
        }
        if(is_minus) res = -res;
        if(res > INT_MAX || res < INT_MIN)  return INT_MAX;
        return res;
    }
};

30. 串联所有单词的子串

哈希表 + 滑动窗口

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
        vector<int> ans;
        if(words.empty()) return ans; //不过看数据范围,没有空的,所以不需要
        //很难,终于弄懂了,分组一段一段的匹配,哈希表,cnt记录滑动窗口有效的子串个数
        int len = s.length(), n = words.size(), w = words[0].length(), cnt = 0;
        unordered_map<string, int> tot; //维护一个总的哈希表
        for(auto& s : words) tot[s]++;
        //将偏移量i从0~w-1分为w组,维护一个滑动窗口,j左边n*w长度才为窗口内容(也就是j不包含)
        for(int i = 0; i < w; i++){
            cnt = 0;//每走完一层就将cnt清零,麻了找了好久的错
            unordered_map<string, int> window;//存放窗口内的子串出现次数
            for(int j = i; j + w <= len; j += w){
                //左边出窗口一个单词
                if(j >= i + n * w){//此时左边才至少有m*w长度
                    auto word = s.substr(j - n * w, w);
                    if(tot[word] >= window[word]) cnt--;//说明是有效的子串,出表,cnt--
                    window[word]--;
                }
                //右边入窗口一个单词
                auto word = s.substr(j, w);
                window[word]++;
                if(window[word] <= tot[word]) cnt++;//说明是有效子串++
                if(cnt == n) ans.push_back(j - (n -  1) * w);
                //为什么是n-1,是因为右边窗口已经进入,但j还没更新
            }
        }
        return ans;
    }
};

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:01:27  更:2022-04-22 19:03:36 
 
开发: 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/26 7:20:59-

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