赞
踩
78.给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:输入:nums = [0]
输出:[[],[0]]
提示:
1 <= nums.length <= 10
-10 <= nums[i] <= 10
nums 中的所有元素 互不相同
有想法,为空返回空,接下来就是上一个+上一个的组合里加新元素的所有。实现起来很困难。
- class Solution {
- public List<List<Integer>> subsets(int[] nums) {
- List<List<Integer>> res=new ArrayList<>();
- List<Integer> temp=new ArrayList<>();
- //先放一个空进来
- res.add(temp);
- for(int i=0;i<nums.length;i++){
- //因为内层循环一直在给res做添加,所以必须保存内层循环开始前的尺寸。
- int k=res.size();
- for(int j=0;j<k;j++){
- temp=res.get(j);
- //为什么这里一定要新建一个temp1?add方法的返回值是一个对象的引用,不是一个简单的值!!!
- List<Integer> temp1=new ArrayList<>(temp);
- temp1.add(nums[i]);
- res.add(temp1);
- }
- }
- return res;
- }
- }

答案的递归法:
- class Solution {
- List<Integer> t = new ArrayList<Integer>();
- List<List<Integer>> ans = new ArrayList<List<Integer>>();
- public List<List<Integer>> subsets(int[] nums) {
- dfs(0, nums);
- return ans;
- }
-
- public void dfs(int cur, int[] nums) {
- if (cur == nums.length) {
- ans.add(new ArrayList<Integer>(t));
- return;
- }
- t.add(nums[cur]);
- dfs(cur + 1, nums);
- t.remove(t.size() - 1);
- dfs(cur + 1, nums);
- }
- }

1.动态规划
- class Solution {
- public List<List<Integer>> subsets(int[] nums) {
- List<List<Integer>> res=new ArrayList<>();
- List<Integer> initSub=new ArrayList<>();
- res.add(initSub);//加一个null
- for (int i = 0; i < nums.length; i++) {
- int time=res.size();
- for (int j = 0; j < time; j++) {
- List<Integer> list=res.get(j);
- List<Integer> sub=new ArrayList<>(list);
- sub.add(nums[i]);
- res.add(sub);
- }
- }
- return res;
- }
- }

461.两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。
给你两个整数 x 和 y,计算并返回它们之间的汉明距离。
示例 1:
输入:x = 1, y = 4
输出:2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
示例 2:输入:x = 3, y = 1
输出:1
提示:
0 <= x, y <= 231 - 1
- class Solution {
- public int hammingDistance(int x, int y) {
- int res=x^y;
- int num=0;
- while(res!=0){
- int temp=res&1;
- num+=temp;
- res=res>>1;
- }
- return num;
- }
- }
94. 给定一个二叉树的根节点 root ,返回它的 中序 遍历。示例 1:
输入:root = [1,null,2,3]
输出:[1,3,2]
示例 2:输入:root = []
输出:[]
示例 3:输入:root = [1]
输出:[1]
示例 4:
输入:root = [1,2]
输出:[2,1]
示例 5:
输入:root = [1,null,2]
输出:[1,2]
提示:
树中节点数目在范围 [0, 100] 内
-100 <= Node.val <= 100
一开始执迷于把链表拿到复制,后来想起可以自己写一个带链表的方法。
- class Solution {
- public List<Integer> inorderTraversal(TreeNode root) {
- List<Integer> list=new ArrayList<Integer>();
- inorder(root,list);
- return list;
- }
- public static void inorder(TreeNode root,List<Integer> res){
- if(root==null){
- res=null;
- return;
- }
- if(root.left!=null){
- inorder(root.left,res);
- }
- res.add(root.val);
- if(root.right!=null){
- inorder(root.right,res);
- }
- }
- }

1.迭代-迭代的本质是维护一个空间复杂度为n的栈。
- class Solution {
- public List<Integer> inorderTraversal(TreeNode root) {
- List<Integer> list=new ArrayList<Integer>();
- //迭代法,维护一个队列存储结果
- Deque<TreeNode> deque=new LinkedList<>();
- while(root!=null||!deque.isEmpty()){
- while(root!=null){
- deque.push(root);
- root=root.left;
- }
- root=deque.pop();
- list.add(root.val);
- //
- root=root.right;
- }
- return list;
- }
- }

2.Morris中序遍历-莫里斯遍历
- class Solution {
- public List<Integer> inorderTraversal(TreeNode root) {
- List<Integer> res = new ArrayList<Integer>();
- TreeNode predecessor = null;
- while(root!=null){
- if(root.left!=null){
- //向左走一步
- predecessor=root.left;
- while(predecessor.right!=null){
- //走到左子树的最右节点
- predecessor=predecessor.right;
- }
- //让根节点称为最右节点的右节点,并剪断根节点的左树
- predecessor.right=root;
- TreeNode temp=root.left;
- root.left=null;
- root=temp;
- }else{
- //现在左边的树已经完全变成了一个链表,只有右节点了,
- //所以往右走,如果后面又遇到了有左节点的节点,往左走一步,继续噶右树,类似递归
- res.add(root.val);
- root=root.right;
- }
- }
- return res;
- }
- }

226.给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例 1:
输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]
示例 2:输入:root = [2,1,3]
输出:[2,3,1]
示例 3:输入:root = []
输出:[]
提示:
树中节点数目范围在 [0, 100] 内
-100 <= Node.val <= 100
递归就完事了
- class Solution {
- public TreeNode invertTree(TreeNode root) {
- if(root==null){
- return null;
- }
- TreeNode temp1=invertTree(root.left);
- TreeNode temp2=invertTree(root.right);
- root.left=temp2;
- root.right=temp1;
- return root;
- }
- }
想想迭代怎么做。
- class Solution {
- public TreeNode invertTree(TreeNode root) {
- //递归终止条件
- if(root == null) {
- return null;
- }
- Stack<TreeNode> stack = new Stack<>();
- stack.push(root);
- while(!stack.isEmpty()) {
- //当前节点出栈
- TreeNode node = stack.pop();
- //将当前节点的左右子树交换
- TreeNode tmp = node.right;
- node.right = node.left;
- node.left = tmp;
- //右子树入栈
- if(node.right != null) {
- stack.push(node.right);
- }
- //左子树入栈
- if(node.left != null) {
- stack.push(node.left);
- }
- }
- return root;
- }
- }

96.给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
示例 1:
输入:n = 3
输出:5
示例 2:输入:n = 1
输出:1
提示:
1 <= n <= 19
1.动态规划

- class Solution {
- public int numTrees(int n) {
- int[] G=new int[n+1];
- G[0]=1;
- G[1]=1;
- for(int i=2;i<=n;i++){
- for(int j=1;j<=i;j++){
- G[i]+=G[j-1]*G[i-j];
- }
- }
- return G[n];
- }
- }
2.数学公式法

- class Solution {
- public int numTrees(int n) {
- // 提示:我们在这里需要用 long 类型防止计算过程中的溢出
- long C = 1;
- for (int i = 0; i < n; ++i) {
- C = C * 2 * (2 * i + 1) / (i + 2);
- }
- return (int) C;
- }
- }
101.给你一个二叉树的根节点 root , 检查它是否轴对称。
示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
提示:
树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100
进阶:你可以运用递归和迭代两种方法解决这个问题吗?
1.递归 -一开始就想到这个方法了,甚至想到了用两个根节点,但是把问题想复杂了,老是去判断子节点,应该直接判断根节点。
- class Solution {
- public boolean isSymmetric(TreeNode root) {
- return check(root,root);
- }
- public boolean check(TreeNode p,TreeNode q){
- if(p==null&&q==null){
- return true;
- }
- if(p==null||q==null){
- return false;
- }
- return (p.val==q.val)&&check(p.left,q.right)&&check(p.right,q.left);
- }
- }
2.迭代-使用到队列和两个方法,offer和poll方法,其作用类似于add和remove,但是不会抛出异常,只会返回false和null。
- class Solution {
- public boolean isSymmetric(TreeNode root) {
- return check(root,root);
- }
- public boolean check(TreeNode p,TreeNode q){
- Queue<TreeNode> queue=new LinkedList<>();
- queue.offer(p);
- queue.offer(q);
- while(!queue.isEmpty()){
- TreeNode temp1=queue.poll();
- TreeNode temp2=queue.poll();
- if(temp1==null&&temp2==null){
- continue;
- }
- if(temp1==null||temp2==null){
- return false;
- }
- if(temp1.val!=temp2.val){
- return false;
- }
- queue.offer(temp1.left);
- queue.offer(temp2.right);
- queue.offer(temp1.right);
- queue.offer(temp2.left);
-
- }
- return true;
- }
- }

48.给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
提示:
n == matrix.length == matrix[i].length
1 <= n <= 20
-1000 <= matrix[i][j] <= 1000
1.先上下翻,再对角线翻。
- class Solution {
- public void rotate(int[][] matrix) {
- int x=matrix.length;
- int temp;
- //左右翻一次
- for(int i=0;i<(x/2);i++){
- for(int j=0;j<x;j++){
- temp=matrix[i][j];
- matrix[i][j]=matrix[x-1-i][j];
- matrix[x-1-i][j]=temp;
- }
- }
- //再沿对角线来一次
- for(int i=0;i<x;i++){
- for(int j=0;j<i;j++){
- temp=matrix[i][j];
- matrix[i][j]=matrix[j][i];
- matrix[j][i]=temp;
- }
- }
- }
- }

2.使用辅助数组-平平无奇
- class Solution {
- public void rotate(int[][] matrix) {
- int n = matrix.length;
- int[][] matrix_new = new int[n][n];
- for (int i = 0; i < n; ++i) {
- for (int j = 0; j < n; ++j) {
- matrix_new[j][n - i - 1] = matrix[i][j];
- }
- }
- for (int i = 0; i < n; ++i) {
- for (int j = 0; j < n; ++j) {
- matrix[i][j] = matrix_new[i][j];
- }
- }
- }
- }

3.原地翻转-一直转反了方向emo了
- class Solution {
- public void rotate(int[][] matrix) {
- int n = matrix.length;
- for (int i = 0; i < n / 2; ++i) {
- for (int j = 0; j < (n + 1) / 2; ++j) {
- int temp = matrix[i][j];
- matrix[i][j] = matrix[n - j - 1][i];
- matrix[n - j - 1][i] = matrix[n - i - 1][n - j - 1];
- matrix[n - i - 1][n - j - 1] = matrix[j][n - i - 1];
- matrix[j][n - i - 1] = temp;
- }
- }
- }
- }
46.给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:输入:nums = [0,1]
输出:[[0,1],[1,0]]
示例 3:输入:nums = [1]
输出:[[1]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums 中的所有整数 互不相同
和那个子集很像,于是自己尝试写了一下,差点忘记add这个坏东西。
- class Solution {
- public List<List<Integer>> permute(int[] nums) {
- //回溯
- List<List<Integer>> res=new ArrayList<>();
- List<Integer> temp=new ArrayList<>();
- //找到nums长度-1的数组的结果,假设一共k个数组
- //然后把nums[i]插到k个数组的所有位置,一共nums.length个位置
- //每次用temp存储插好的数组,插一次就往res里加一次
- //返回最终结果
- if(nums.length==1){
- temp.add(nums[0]);
- res.add(temp);
- return res;
- }
- int[] pre=new int[nums.length-1];
- for(int i=0;i<pre.length;i++){
- pre[i]=nums[i];
- }
- List<List<Integer>> preRes=permute(pre);
- for(int i=0;i<preRes.size();i++){
- for(int j=0;j<nums.length;j++){
- temp=preRes.get(i);
- List<Integer> temp1=new ArrayList<>(temp);
- temp1.add(j,nums[nums.length-1]);
- res.add(temp1);
- }
- }
- return res;
- }
- }

虽然一会忘记add,一会忘记写递归结束条件,一会写错条件,但最后靠自己写出来,挺高兴,说明子集那个题目也学会了。
104.给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
一个是递归,看左右子树的深度最大值再加1;一个是广度优先搜索,感觉和那个轴对称类似,使用队列来存进来的节点。
1.递归
- class Solution {
- public int maxDepth(TreeNode root) {
- if(root==null){
- return 0;
- }else{
- int leftDepth=maxDepth(root.left);
- int rightDepth=maxDepth(root.right);
- return Math.max(leftDepth,rightDepth)+1;
- }
- }
- }
2.广度优先搜索树
差点new queue去了,记得底层用链表。
- class Solution {
- public int maxDepth(TreeNode root) {
- Queue<TreeNode> queue=new LinkedList<>();
- if(root==null){
- return 0;
- }
- queue.offer(root);
- int num=0;
- //只要队列不为空,就说明没处理完所有节点
- while(!queue.isEmpty()){
- int size=queue.size();
- //类似递归的思想,来遍历树
- while(size>0){
- TreeNode temp=queue.poll();
- if(temp.left!=null){
- queue.offer(temp.left);
- }
- if(temp.right!=null){
- queue.offer(temp.right);
- }
- size--;
- }
- num++;
- }
- return num;
- }
- }

102.给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:输入:root = [1]
输出:[[1]]
示例 3:输入:root = []
输出:[]
提示:
树中节点数目在范围 [0, 2000] 内
-1000 <= Node.val <= 1000
感觉类似前几个题目,用队列存储广度优先搜索。
- class Solution {
- public List<List<Integer>> levelOrder(TreeNode root) {
- List<List<Integer>> res=new ArrayList<>();
- List<Integer> temp=new ArrayList<>();
- TreeNode curr=root;
- if(curr==null){
- return res;
- }
- //根节点那一层
- temp.add(curr.val);
- List<Integer> temp1=new ArrayList<>(temp);
- res.add(temp1);
- //下一层
- //还得是队列
- Queue<TreeNode> q=new LinkedList<>();
- q.offer(root);
- while(!q.isEmpty()){
- int size=q.size();
- List<Integer> l=new ArrayList<>();
- while(size>0){
- TreeNode treeNode=q.poll();
- if(treeNode.left!=null){
- q.offer(treeNode.left);
- l.add(treeNode.left.val);
- }
- if(treeNode.right!=null){
- q.offer(treeNode.right);
- l.add(treeNode.right.val);
- }
- size--;
- }
- //这一层遍历完了
- List<Integer> r=new ArrayList<>(l);
- if(r.size()>0){
- res.add(r);
- }
- }
- return res;
- }
- }

答案也是广度优先搜索,不过略有不同。
75.给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:输入:nums = [2,0,1]
输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2
进阶:
你可以不使用代码库中的排序函数来解决这道题吗?
你能想出一个仅使用常数空间的一趟扫描算法吗?
本质上是要写一个含重复数字的排序算法,要求空间复杂度为O(1),时间复杂度为O(n)。
1.双指针搞一哈-应该有两种解法
- class Solution {
- public void sortColors(int[] nums) {
- //双指针,指向头部
- //遍历一次,如果遇到0,一起移动,遇到1,只有right移动
- int left=0;
- int right=0;
- for(int i=0;i<nums.length;i++){
- if(nums[i]==0){
- int temp=nums[i];
- nums[i]=nums[left];
- nums[left]=temp;
- //
- if(left<right){
- int temp1=nums[i];
- nums[i]=nums[right];
- nums[right]=temp1;
- }
- left++;
- right++;
- }else if(nums[i]==1){
- int temp=nums[i];
- nums[i]=nums[right];
- nums[right]=temp;
- right++;
- }
- }
- }
- }


如果left和right之间有1了,那么这个0就和1交换了,所以需要在换一次。如果left和right一直相等,那就随便换。
- class Solution {
- public void sortColors(int[] nums) {
- //双指针,一个指向头部,一个指向尾部
- //0放前面,2放后面
- int left=0;
- int right=nums.length-1;
- for(int i=0;i<nums.length;i++){
- //如果交换的也是个2,且i没有大过right,不然会多交换
- while(i<right&&nums[i]==2){
- int temp=nums[i];
- nums[i]=nums[right];
- nums[right]=temp;
- right--;
- }
- if(nums[i]==0){
- int temp=nums[i];
- nums[i]=nums[left];
- nums[left]=temp;
- left++;
- }
- }
- }
- }

2.单指针遍历两遍,第一遍把所有0放前面,第二遍把所有1放0后面。
- class Solution {
- public void sortColors(int[] nums) {
- int left=0;
- //单指针遍历两次
- //第一次先将所有的0放到数组前面
- //第二次将所有的1放在0后面
- for(int i=0;i<nums.length;i++){
- if(nums[i]==0){
- int temp=nums[i];
- nums[i]=nums[left];
- nums[left]=temp;
- left++;
- }
- }
- //此时left指向最后一个0的下一个
- for(int i=left;i<nums.length;i++){
- if(nums[i]==1){
- int temp=nums[i];
- nums[i]=nums[left];
- nums[left]=temp;
- left++;
- }
- }
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。