前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >链表问题、单调栈-LeetCode 430、725、168、1290、215、1019、503(递减型单调栈)

链表问题、单调栈-LeetCode 430、725、168、1290、215、1019、503(递减型单调栈)

作者头像
算法工程师之路
发布2019-12-24 17:29:11
6120
发布2019-12-24 17:29:11
举报

作者:TeddyZhang,公众号:算法工程师之路

链表问题(三)、单调栈:

LeetCode # 430 725 168 1290 215 1019 503

1

编程题

【LeetCode #430】扁平化多级双向链表

您将获得一个双向链表,除了下一个和前一个指针之外,它还有一个子指针,可能指向单独的双向链表。这些子列表可能有一个或多个自己的子项,依此类推,生成多级数据结构,如下面的示例所示。

扁平化列表,使所有结点出现在单级双链表中。您将获得列表第一级的头部。

示例: 输入: 1---2---3---4---5---6--NULL | 7---8---9---10--NULL | 11--12--NULL 输出: 1-2-3-7-8-11-12-9-10-4-5-6-NULL

解题思路:

把上面的图向左旋转90度,就会发现其实一个二叉树,然后这道题的实质就是二叉树的先序遍历,下面使用先序遍历的迭代法,不知道大家忘了没有。在遍历完成的同时进行双向链表的构建,由于其还有child指针,应该置为nullptr. 注意:先,中,后序遍历都是指的根节点的访问顺序。

代码语言:javascript
复制
/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* prev;
    Node* next;
    Node* child;
};
*/
class Solution {
public:
    Node* flatten(Node* head) {
        stack<Node*> sta;
        if (head == nullptr) return nullptr;
        sta.push(head);
        Node* pre = nullptr;
        while(!sta.empty()) {
            Node* tmp = sta.top();
            sta.pop();
            if (tmp->next != nullptr) sta.push(tmp->next);
            if (tmp->child != nullptr) {   // 双向链表中child为空
                sta.push(tmp->child);
                tmp->child = nullptr;
            }
            if(pre) {   // 构建双向链表
                pre->next = tmp;
                tmp->prev = pre;
            }
            pre = tmp;
        }
        return head;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/flatten-a-multilevel-doubly-linked-list

【LeetCode #725】分割链表

给定一个头结点为 root 的链表, 编写一个函数以将链表分隔为 k 个连续的部分。 每部分的长度应该尽可能的相等: 任意两部分的长度差距不能超过 1,也就是说可能有些部分为 null。 这k个部分应该按照在链表中出现的顺序进行输出,并且排在前面的部分的长度应该大于或等于后面的长度。 返回一个符合上述规则的链表的列表。 举例:1->2->3->4, k = 5 // 5 结果 [ [1], [2], [3], [4], null ]

示例 1: 输入: root = [1, 2, 3], k = 5 输出: [[1],[2],[3],[],[]] 解释: 输入输出各部分都应该是链表,而不是数组。 例如, 输入的结点 root 的 val= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。 第一个输出 output[0] 是 output[0].val = 1, output[0].next = null。 最后一个元素 output[4] 为 null, 它代表了最后一个部分为空链表。

解题思路:

常规思路,首先根据总长度和k值,计算得到每个分割区间的长度,然后利用pre节点得到每个区间的最后一个节点,使其指向为nullptr,遍历完整个链表即可! 遍历完成,如果res.size()小于k值,那么向res中添加nullptr即可,使其长度为k.

代码语言:javascript
复制
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<ListNode*> splitListToParts(ListNode* root, int k) {
        int length = ;
        vector<ListNode*> res;
        ListNode* cur = root;
        while(cur != nullptr) {
            length++;
            cur = cur->next;
        }
        int nums = length / k;
        int left = length % k;
        cur = root;
        ListNode* pre = nullptr;
        while(cur != nullptr) {
            int tmp_nums = left ? nums+ : nums;
            if (left > )  left -= ;    // left >= 0
            res.push_back(cur);
            while(tmp_nums--) {
                pre = cur;
                cur = cur->next;
            }
            if (pre)  pre->next = nullptr;   // 进行链表分割
        }
        int tt = k - res.size();
        while(tt--) 
            res.push_back(nullptr);
        return res;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/split-linked-list-in-parts

【LeetCode #168】Excel表列名称

给定一个正整数,返回它在 Excel 表中相对应的列名称。

例如, 1 -> A 2 -> B 3 -> C … 26 -> Z 27 -> AA 28 -> AB …

示例 1: 输入: 1 输出: "A"

解题思路:也就是一个26进制的问题

代码语言:javascript
复制
class Solution {
public:
    string convertToTitle(int n) {
        char ch = 'A';
        string res = "";
        while(n != ) {
            n--;
            res += (ch + n % );
            n /= ;
        }
        reverse(res.begin(), res.end());
        return res;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/excel-sheet-column-title

【LeetCode #1290】二进制链表转整数

给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。 请你返回该链表所表示数字的 十进制值 。

示例 1: 输入:head = [1,0,1] 输出:5 解释:二进制数 (101) 转化为十进制数 (5)

解题思路:

复习下链表反转,首先翻转链表,接着遍历链表即可

代码语言:javascript
复制
class Solution {
public:
    int getDecimalValue(ListNode* head) {
        ListNode* pre = nullptr;
        while(head != nullptr) {
            ListNode* next = head->next;
            head->next = pre;
            pre = head;
            head = next;
        }
        int sum = ;
        int tmp = ;
        while(pre != nullptr) {
            sum += (pre->val * tmp);
            tmp *= ;
            pre = pre->next;
        }
        return sum;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/convert-binary-number-in-a-linked-list-to-integer

【LeetCode #215】数组中的第K个最大元素

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5

解题思路:

大根堆的创建,注意在priority_queue中建立大根堆要使用less函数(默认),小根堆使用greater函数,以及lambda表达式和priority_queue的结合使用!

代码语言:javascript
复制
class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        if(nums.size() == ) return ;
        auto cmp = [](int a, int b) {
            return a <= b;
        };
        priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);
        for(auto i: nums) {
            pq.push(i);
        }
        while((k--) > ){
            pq.pop();
        }
        return pq.top();
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array

【LeetCode #1019】链表中的下一个更大节点

给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, … 。 每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且 node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。 返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。

注意:在下面的示例中,诸如 [2,1,5] 这样的输入(不是输出)是链表的序列化表示,其头节点的值为 2,第二个节点值为 1,第三个节点值为 5 。

示例 1: 输入:[2,7,4,3,5] 输出:[7,0,5,5,0]

解题思路:

构建一个单调递减的单调栈,比如[2,7,4,3,5],遍历压入栈中,当栈中元素为[2]时,满足单调栈,遍历到7,由于7 > 2,则不满足,应将所有小于7的元素全部pop,这样才能满足单调栈,因此遍历结束后,单调栈中只会剩余[7, 5],将其置零即可!

代码语言:javascript
复制
class Solution {
public:
    vector<int> nextLargerNodes(ListNode* head) {
        vector<int> res;
        stack<int> sta;    // 构建单调栈,存放单调递减的数值序列
        int i = ;
        while(head != nullptr) {
            while(!sta.empty() && head->val > res[sta.top()]){
                res[sta.top()] = head->val;
                sta.pop();
            }

            res.push_back(head->val);
            sta.push(i++);
            head = head->next;
        }
        while(!sta.empty()) {
            res[sta.top()] = ;
            sta.pop();
        }
        return res;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-node-in-linked-list

【LeetCode #503】下一个更大的元素 II

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

示例 1: 输入: [1,2,1] 输出: [2,-1,2] 解释: 第一个 1 的下一个更大的数是 2; 数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

解题思路:

这道题与上面的题是一个解法,使用单调递减的单调栈处理,不同的是上面由于是链表,不支持index,需要先拷贝到res中,再进行处理。而这道题目本身就是vector,因此不再需要将数据拷贝到res中,可以直接通过索引赋值! 本题最后一个元素是第一个元素,属于循环数组,我们遍历两次就可以了!

代码语言:javascript
复制
class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int n = nums.size();
        vector<int> res(n, -1);
        stack<int> sta;
        for(int i = ; i < n*; i++) {
            while(!sta.empty() && nums[sta.top()] < nums[i % n]) {
                res[sta.top()] = nums[i % n];
                sta.pop();
            }
            if (i < n) {
                sta.push(i);
            }
        }
        return res;
    }
};

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/next-greater-element-ii

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法工程师之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档