力扣爆刷第168天之TOP200五连刷106-110(每日温度单调栈、盛水最多滑动窗口、全排列回溯)
文章目录
一、138. 随机链表的复制
题目链接:https://leetcode.cn/problems/copy-list-with-random-pointer/description/
思路:本题求的是随机链表的复制,其实就是把链表复制一份出来,但是要求深拷贝,其实也很简单,需要先把链表next的这一条链给复制一遍,并且在复制的过程中用map进行记录,原链表节点为key,拷贝链表节点为value,这样在复制完next链以后,再遍历一遍原链表的每一个节点的random,就可以利用map找到在拷贝链表中对应的节点。
class Solution {
public Node copyRandomList(Node head) {
Map<Node, Node> map = new HashMap<>();
Node root = new Node(-1);
Node p1 = head, p2 = root;
while(p1 != null) {
p2.next = new Node(p1.val);
p2 = p2.next;
map.put(p1, p2);
p1 = p1.next;
}
p1 = head;
p2 = root.next;
while(p1 != null) {
p2.random = map.get(p1.random);
p1 = p1.next;
p2 = p2.next;
}
return root.next;
}
}
二、739. 每日温度
题目链接:https://leetcode.cn/problems/daily-temperatures/description/
思路:求对于每一天来说,下一个大于今天温度的天,在几天之后,让求这个。一看就是使用单调栈,本质上维护一个从栈底到栈顶单调递减的栈,如果当前元素的值大于栈顶了,那么栈顶出栈,对于栈顶元素来说,外面的这个元素就是第一个大于他的,然后还要继续出栈,直到栈内没有小于外部元素的元素即可。
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int len = temperatures.length;
int[] res = new int[len];
LinkedList<Integer> stack = new LinkedList<>();
for(int i = 0; i < len; i++) {
while(!stack.isEmpty() && temperatures[i] > temperatures[stack.peek()]) {
int t = stack.pop();
res[t] = i - t;
}
stack.push(i);
}
return res;
}
}
三、136. 只出现一次的数字
题目链接:https://leetcode.cn/problems/single-number/description/
思路:本题是一个利用运算符的题,只有一个元素出现一次,其他都出现两次,那么可以利用异或的特性,相同为0,不同为1。
举个例子:
1 1 0、0 0 1、 1 1 0一共三个数:
1 1 0 ^ 0 0 1 = 1 1 1;
1 1 1 ^ 1 1 0 = 0 0 1.
class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for(int n : nums) {
res ^= n;
}
return res;
}
}
四、11. 盛最多水的容器
题目链接:https://leetcode.cn/problems/container-with-most-water/
思路:求左右边界与x轴围起来的最大面积,不同与接雨水,本题只需要维护一个最大的滑动窗口,不断记录窗口面积,如果左边界小于右边界,那么可以把左边界向右移动,如果右边界小于左边界,那么可以把右边界向左移动。这样当左右边界相遇,在过程中一定记录下来了最大窗口面积。
class Solution {
public int maxArea(int[] height) {
int left = 0, right = height.length-1;
int max = 0;
while(left < right) {
max = Math.max(max, Math.min(height[left], height[right]) * (right - left));
if(height[left] <= height[right]) left++;
else right--;
}
return max;
}
}
五、47. 全排列 II
题目链接:https://leetcode.cn/problems/permutations-ii/description/
思路:我先把回溯题的心法写在下面:
回溯类型的题目一共就分两类:组合和排列。
然后又细分为:
①、元素无重,不可复选。
②、元素可重,不可复选。
③、元素无重,可复选。
本题是排列,而且有重复元素,不可复选,那么可以排列一下,又因为是排序,不需要指定起始位置,每次递归遍历都是从0开始,所以需要纵向去重,避免单个元素重复使用。另外又因为数组本身就有重复元素,如果1 1 2,排列之后会出现 第一个1和第二个1,与,第二个1和第一个1.那么需要横向去重,这个是需要排序使用的。
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] flag;
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
flag = new boolean[nums.length];
backTracking(nums);
return res;
}
void backTracking(int[] nums) {
if(list.size() == nums.length) {
res.add(new ArrayList(list));
return;
}
for(int i = 0; i < nums.length; i++) {
if(flag[i] || (i > 0 && nums[i] == nums[i-1]) && !flag[i-1]) continue;
flag[i] = true;
list.add(nums[i]);
backTracking(nums);
flag[i] = false;
list.remove(list.size()-1);
}
}
}