数组
移除元素
https://leetcode-cn.com/problems/remove-element/
- 暴力法
找到目标值后,后面的元素依次向前移动,覆盖掉目标值
1 | public int removeElement(int[] nums, int val) { |
- 快慢指针法
快指针把不是目标值的元素移动到慢指针位置
1 | public int removeElement(int[] nums, int val) { |
长度最小的子数组
https://leetcode-cn.com/problems/minimum-size-subarray-sum/
- 暴力法
遍历所有窗口的时候,不是生成某长度的窗口,让窗口移动,这样需要重复计算这个窗口里面数字的和。而是按照不同的起点分类,每个起点遍历不同长度的窗口,这样可以利用已经计算出的结果,也可以遍历完所有窗口。
1 | public int minSubArrayLen(int target, int[] nums) { |
- 滑动窗口
滑动窗口是双指针的一种,sum>=target 收缩 sum<target 扩大
1 | public int minSubArrayLen(int target, int[] nums) { |
- 滑动窗口优化
核心思想还是sum >= target 左侧收缩 sum<target 右侧扩大
不过使用了双重循环,外循环负责移动右侧,内循环赋值移动左侧
当left 与 right 重合时,sum的值为0,while循环停止,nums不会取到right右侧的值,right不会越界,所以left也不会越界
1 | public int minSubArrayLen(int target, int[] nums) { |
螺旋矩阵Ⅱ
https://leetcode.cn/problems/spiral-matrix-ii/
1 | private int counter = 1; |
螺旋矩阵
https://leetcode.cn/problems/spiral-matrix/
1 | private List<Integer> result = new LinkedList<>(); |
链表
删除链表中的元素
https://leetcode.cn/problems/remove-linked-list-elements/
1 | public ListNode removeElements(ListNode head, int val) { |
设计链表
https://leetcode.cn/problems/design-linked-list/
定义内部节点类
判断索引是否有效 index >=size index < 0无效
找到index位置节点
current设置为虚拟节点,当index等于0时,current要移动到头节点,所以for要写成
// 模仿对数组的遍历,i相当于数组的下标
for (int i=0; i<=index; i++) {
current = current.next;
}
1 | class MyLinkedList { |
反转链表
https://leetcode.cn/problems/reverse-linked-list/
1 | class Solution { |
两两交换节点
https://leetcode.cn/problems/swap-nodes-in-pairs/
1 | public ListNode swapPairs(ListNode head) { |
链表相交
https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/
移动到相同长度的位置
1 | public ListNode getIntersectionNode(ListNode headA, ListNode headB) { |
环形链表
https://leetcode.cn/problems/linked-list-cycle-ii/
- 集合
1
2
3
4
5
6
7
8
9
10
11public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null) {
if (!set.add(head)) {
return head;
}
head = head.next;
}
ListNode result = null;
return result;
} - 数学
1 | public ListNode detectCycle(ListNode head) { |
哈希表
字母异位词
https://leetcode.cn/problems/valid-anagram/
数组其实就是一种简单的哈希表,key是index,value是元素的值
小写字母,26个,新建长度26的数组
记录s每个字母的数量++
记录t每个字母的数量–
如果nums有非零元素,说明有数量不一样的字母
1 | public boolean isAnagram(String s, String t) { |
交集
https://leetcode.cn/problems/intersection-of-two-arrays/
set1 去重nums1
set1中contains nums2中的元素
就就加入set2
set2变成数组
1 | public int[] intersection(int[] nums1, int[] nums2) { |
快乐数
https://leetcode.cn/problems/happy-number/
利用好题目给的条件,会循环的,只要找到一个相同的,就开始死循环了,平方和永远无法变成1,直接return false
1 | public boolean isHappy(int n) { |
两数之和
https://leetcode.cn/problems/two-sum/
- 暴力
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
for (int i=0; i<nums.length; i++) {
for (int j=0; j<nums.length; j++) {
if (j == i) {
continue;
}
if (nums[i] + nums[j] == target) {
result[0] = i;
result[1] = j;
return result;
}
}
}
return result;
} - map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public int[] twoSum(int[] nums, int target) {
int[] result = new int[2];
// map key=nums[i] value=i
Map<Integer, Integer> map = new HashMap<>();
for (int i=0; i<nums.length; i++) {
int another = target - nums[i];
if (map.containsKey(another)) {
result[0] = map.get(another);
result[1] = i;
return result;
} else {
// 找不到后才加入,防止another与当前nums[i]重复
map.put(nums[i], i);
}
}
return result;
}
四数相加
https://leetcode.cn/problems/4sum-ii/
- 回溯 超时x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38private int[] nums1;
private int[] nums2;
private int[] nums3;
private int[] nums4;
private int result;
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
this.nums1 = nums1;
this.nums2 = nums2;
this.nums3 = nums3;
this.nums4 = nums4;
this.backtrack(0, 0);
return this.result;
}
private void backtrack(int depth, int sum) {
if (depth == 4) {
if (sum == 0) {
this.result++;
}
return;
}
for (int i=0; i<this.nums1.length; i++) {
backtrack(depth + 1, sum + this.getNums(depth)[i]);
}
}
private int[] getNums(int depth) {
if (depth == 0) {
return nums1;
} else if (depth == 1) {
return nums2;
} else if (depth == 2) {
return nums3;
} else {
return nums4;
}
} - 四层循环暴力 超时x
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int result = 0;
int n = nums1.length;
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
for (int k=0; k<n; k++) {
for (int l=0; l<n; l++) {
if (nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0) {
result++;
}
}
}
}
}
return result;
} - 使用map
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer, Integer> map = new HashMap<>();
for (int a : nums1) {
for (int b : nums2) {
int temp = a + b;
map.put(temp, map.getOrDefault(temp, 0) + 1);
}
}
int result = 0;
for (int c : nums3) {
for (int d : nums4) {
// a + b == 0 - c - d时,a b和当前c d组合都满足条件,情况数就是a+b的次数
result += map.getOrDefault(0 - c - d, 0);
}
}
return result;
}
三数之和
https://leetcode.cn/problems/3sum/
- 双指针
如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
1 | public List<List<Integer>> threeSum(int[] nums) { |
- 回溯 超时
回溯也是一种暴力搜索,很容易超时,只不过比for循环复杂一些,但是本质还是暴力搜索
1 | private List<List<Integer>> result = new ArrayList<>(); |
四数之和
https://leetcode.cn/problems/4sum/
- 回溯 勉强过
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32private List<List<Integer>> result = new ArrayList<>();
private List<Integer> path = new ArrayList<>();
public List<List<Integer>> fourSum(int[] nums, int target) {
if (nums.length <= 3) {
return this.result;
}
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
this.backtrack(nums, 0, used, target);
return this.result;
}
private void backtrack(int[] nums, int startIndex, boolean[] used, int target) {
if (this.path.size() == 4) {
if (target == 0) {
this.result.add(new ArrayList(this.path));
}
return;
}
for (int i=startIndex; i<nums.length; i++) {
if (i > 0 && !used[i-1] && nums[i-1]==nums[i]) {
continue;
}
used[i] = true;
this.path.add(nums[i]);
backtrack(nums, i+1, used, target - nums[i]);
used[i] = false;
this.path.remove(this.path.size()-1);
}
} - 双指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums);
for (int i=0; i<nums.length; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for (int j = i + 1; j < nums.length; j++) {
// 注意去重方式,不能是紧挨上一层循环的元素,相当于回溯遍历去重方式,
// 能和上一层元素相同,但是本层不能使用重复的
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int left = j + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target) {
right--;
// 和上一个值重复了,sum值仍然是一样的,直接循环到不一样的
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
} else if (sum < target) {
left++;
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
} else {
result.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) {
left++;
}
while (left < right && nums[right] == nums[right + 1]) {
right--;
}
}
}
}
}
return result;
}
赎金信
https://leetcode.cn/problems/ransom-note/
- 数组哈希表
记录magazine各个字符的数量
在ransomNote中,减去使用的字符,如果出现负数,说明magazine字符不够用,false
1 | public boolean canConstruct(String ransomNote, String magazine) { |