Day5
翻转二叉树
- 题目:翻转一棵二叉树,使其左右子树互换,形式如下图片:
4 4
/ \ / \
7 2 -> 2 7
/ \ / \ / \ / \
9 6 3 1 1 3 6 9
- 题目解析:二叉树的互换,实际上是左右子树元素的互换,由于树的基本性质,可以较为简单的想到采用递归的方式,但左右子树互换的时候,需要保存互换的值,避免交换错误,具体代码如下:
class Solution {
public TreeNode invertTree(TreeNode root) {
return tranverse(root);
}
public TreeNode tranverse(TreeNode root){
if(root == null)
return null;
//使用 tmp 节点存放交换后的左右子树的元素引用
TreeNode tmp = tranverse(root.right);
root.right = tranverse(root.left);
root.left = tmp;
//返回交换成功后的左右子树
return root;
}
}
环形链表
- 题目:判断一个链表中是否产生了环,注意,不改变链表原来结构,同时,空间复杂度为 \(O(1)\)
- 题目解析:可以循环遍历时使用哈希表记录引用地址,看哈希表中是否已经存在引用。本解采用的主要思路是龟兔思路,快慢指针在成环的链表中,经历 \(n\) 圈后,必会相遇,代码如下:
public class Solution {
public boolean hasCycle(ListNode head) {
if(head == null || head.next == null)
return false;
//快慢指针的初值,使其都能进入循环体中
ListNode slow = head;
ListNode quick = head.next;
while(slow != quick){
//如果快指针能到达 null 说明并没有成环
if(quick == null || quick.next == null)
return false;
slow = slow.next;
quick = quick.next.next;
}
return true;
}
}
组合总和
- 题目:给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。注意,candidates 中的元素可以被无限次选取,同时,像 2,2,3 和 3,2,2 这样的序列被认为是重复序列,不能出现在答案中。
- 题解:很明显的搜索回溯问题,为了避免重复序列,应该设置一个 begin 序号来标明之前元素不能再选取。同时,搜索回溯的过程还应当适当剪枝(本题解是基于排序基础上的剪枝),代码如下:
class Solution {
//存放最终的答案
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates == null || candidates.length == 0)
return null;
//对元素进行排序便于后面的剪枝
Arrays.sort(candidates);
dfs(candidates, target, new ArrayList<Integer>(), 0);
return ans;
}
public void dfs(int[] candidates, int target, List<Integer> stack, int index){
//target 等于 0 说明已经得出一个题解
if(target == 0){
ans.add(new ArrayList<>(stack));
return;
}
for(int i = index; i < candidates.length; i ++){
//剪枝,小元素都超过目标,大元素更不行
if(target - candidates[i] < 0)
break;
stack.add(candidates[i]);
dfs(candidates, target - candidates[i], stack, i);
//添加完题解后,删去刚刚加入的元素,继续遍历
stack.remove(stack.size() - 1);
}
}
}