一、算法思想
1.二分法
2.双指针
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
思路:定住一个数,剩下两个数双向奔赴
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
int len = nums.length;
Arrays.sort(nums);
for(int i = 0; i < len - 2;i++) {
if(i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int start = i + 1;
int end = len - 1;
while(start < end) {
int sum = nums[i] + nums[start] + nums[end];
if(sum == 0) {
res.add(List.of(nums[i], nums[start], nums[end]));
start++;
end--;
while(start < end && nums[start] == nums[start - 1]) {
start++;
}
while(start < end && nums[end] == nums[end + 1]) {
end--;
}
} else if(sum < 0) {
start++;
} else {
end--;
}
}
}
return res;
}
}
18.四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n a、b、c 和 d 互不相同 nums[a] + nums[b] + nums[c] + nums[d] == target 你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
思路:定住两个数,剩下两位双向奔赴
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
int len = nums.length;
Arrays.sort(nums);
for(int i = 0; i < len -3;i++) {
if(i > 0 && nums[i] == nums[i - 1]) {
continue;
}
for(int j = i + 1;j < len;j++) {
if(j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
int start = j + 1;
int end = len - 1;
while(start < end) {
int fourSum = nums[i] + nums[j] + nums[start] + nums[end];
if(fourSum == target) {
res.add(List.of(nums[i], nums[j], nums[start], nums[end]));
start++;
end--;
while(start < end && nums[start] == nums[start - 1]) {
start++;
}
while(start < end && nums[end] == nums[end + 1]) {
end--;
}
} else if(fourSum > target) {
end--;
} else {
start++;
}
}
}
}
return res;
}
}
3.滑动窗口
滑动窗口是双指针的变形,不是左右指针双向奔赴,而是快慢指针沿同一方向移动。
3.无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
思路:快指针往前走,直到遇到重复的字符,快指针停下,慢指针向前走
class Solution {
public int lengthOfLongestSubstring(String s) {
int res = -1;
int len = s.length();
int slow = 0;
int fast = slow;
Set<Character> set = new HashSet<>();
while(fast < len) {
if(set.add(s.charAt(fast))) {
res = Math.max(res, set.size());
fast++;
} else {
set.remove(s.charAt(slow++));
}
}
return Math.max(res, 0);
}
}
219. 存在重复元素 II
给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。
输入:nums = [1,2,3,1], k = 3
输出:true
代码:初始化最大窗口k,窗口没有重复字符,快慢指针同时向前移
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
int len = nums.length;
if(len < 2) {
return false;
}
Set<Integer> set = new HashSet<>();
k = Math.min(len - 1, k);
for(int i = 0; i < k;i++) {
if(!set.add(nums[i])) {
return true;
}
}
int slow = 0;
int fast = k;
while(fast < len) {
if(!set.add(nums[fast])) {
return true;
}
set.remove(nums[slow++]);
fast++;
}
return false;
}
}
4.深度优先搜索
5.广度优先搜索
101. 对称二叉树
给你一个二叉树的根节点 root , 检查它是否轴对称
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
思路:关键点是树1的左节点等于树2的右节点,树1的右节点等于树2的左节点。从Queue中一次poll两次比较。
class Solution {
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root.left);
queue.offer(root.right);
while(!queue.isEmpty()) {
TreeNode node1 = queue.poll();
TreeNode node2 = queue.poll();
if(node1 == null && node2 == null) {
continue;
} else if(node1 == null || node2 == null) {
return false;
} else if(node1.val != node2.val) {
return false;
} else {
queue.offer(node1.left);
queue.offer(node2.right);
queue.offer(node1.right);
queue.offer(node2.left);
}
}
return true;
}
}
103. 二叉树的锯齿形层序遍历
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]
思路:通过queue的大小来明确遍历树时的层级
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
boolean left2Right = true;
while(!queue.isEmpty()) {
int size = queue.size();
List<Integer> curLevel = new ArrayList<>();
for(int i = 0;i < size;i++) {
TreeNode node = queue.poll();
if(node != null) {
queue.offer(node.left);
queue.offer(node.right);
if(left2Right) {
curLevel.add(node.val);
} else {
curLevel.add(0, node.val);
}
}
}
if(!curLevel.isEmpty()) {
res.add(curLevel);
}
left2Right = !left2Right;
}
return res;
}
}
104. 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例: 给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
思路:通过queue的大小来明确遍历树时的层级
class Solution {
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
int dept = 0;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()) {
dept++;
int size = queue.size();
for(int i = 0;i < size;i++) {
TreeNode node = queue.poll();
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
}
}
return dept;
}
}