原题链接: 321c:从链表中移除节点
仅供学习记录。
题目大意
给你一个链表的头节点 head
。
对于列表中的每个节点 node
,如果其右侧存在一个具有 严格更大 值的节点,则移除node
。
返回修改后链表的头节点 head
。
示例 1:
输入:head = [5,2,13,3,8]
输出:[13,8]
解释:需要移除的节点是 5 ,2 和 3 。
- 节点 13 在节点 5 右侧。
- 节点 13 在节点 2 右侧。
- 节点 8 在节点 3 右侧。
示例 2:
输入:head = [1,1,1,1]
输出:[1,1,1,1]
解释:每个节点的值都是 1 ,所以没有需要移除的节点。
提示:
给定列表中的节点数目在范围 [1, 10^5] 内
1 <= Node.val <= 10^5
思路
与739. 每日温度类似,考察单调栈,转化为对每个元素求右边第一个比它大的元素。
首先将链表转化为数组来处理较为方便,以及定义好虚拟结点dummy便于处理头结点的情况。
在本题的单调栈中,栈顶元素小于栈底元素,即递增(若存在递减的逆序对,则逆序对中的后者是多余的)。
代码
/**
* 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* removeNodes(ListNode* head) {
vector<int> nums;
auto dummy = new ListNode(-1);
dummy->next = head;
for(auto cur = head; cur != nullptr; cur = cur->next){
nums.push_back(cur->val);
}
int n = nums.size();
vector<int> res(n, -1);
stack<int> stk;//存储的是下标
for(int i = n - 1; i >= 0; i -- ){
while(stk.size() && nums[i] >= nums[stk.top()]) stk.pop();
if(stk.size()) res[i] = nums[stk.top()];
stk.push(i);
}
// for(const auto &c : res) cout << c << " ";
// cout << endl;
int idx = 0;
for(auto cur = dummy; cur != nullptr; cur = cur->next){
auto p = cur;
while(p->next && res[idx] > 0){
p = p->next;
idx ++;
}
cur->next = p->next;
idx ++;
}
return dummy->next;
}
};
时间复杂度
O(n)