leetcode3

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++;
                }
            }
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值