剑指 offer day15-17

Posted six double seven@

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指 offer day15-17相关的知识,希望对你有一定的参考价值。

257. 二叉树的所有路径

题目:

给你一个二叉树的根节点 root ,按任意顺序 ,返回所有从根节点叶子节点的路径。

题解:

constructPaths函数:

1.参数:当前节点,当前路径,以及最终返回的list集合paths

2.如果当前节点不为空,则将该节点添加到path中;

3.在不为空的基础上,判断当前节点是否为叶子节点,如果为叶子节点则代表这条path结束,将path添加至paths中;如果不是叶子节点,则继续遍历它的左右子树。

    public List<String> binaryTreePaths(TreeNode root) {
        List<String> res = new ArrayList<>();
        constructPaths(root,"",res);
        return res;
    }
    public void constructPaths(TreeNode root, String path, List<String> paths){
        if (root!=null){
            StringBuffer sb = new StringBuffer(path);
            sb.append(Integer.toString(root.val));
            if (root.left==null&&root.right==null){//为叶子节点
                paths.add(sb.toString());
            }else {
                sb.append("->");
                constructPaths(root.left,sb.toString(),paths);
                constructPaths(root.right,sb.toString(),paths);
            }
        }
    }

剑指 Offer 34. 二叉树中和为某一值的路径

题目:

给你二叉树的根节点root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。

题解:

和上一题的思路一致。

    public List<List<Integer>> pathSum(TreeNode root, int target) {
        List<Integer> path = new ArrayList<>();
        List<List<Integer>> res = new ArrayList<>();
        constructPaths(root,0,target,path,res);
        return res;
    }
    public void constructPaths(TreeNode root, int sum,int target,List<Integer> path,List<List<Integer>> paths){

        if (root!=null){
            sum = sum + root.val;
            List<Integer> list = new ArrayList<>(path);//用来获取截止到目前为止路径中的节点
            list.add(root.val);
            if (root.right==null&&root.left==null){
                if (sum==target){
                    paths.add(list);
                }
            }else {
                constructPaths(root.left,sum,target,list,paths);
                constructPaths(root.right,sum,target,list,paths);
            }
        }
    }

剑指 Offer 36. 二叉搜索树与双向链表

题目:

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

题解:

1.对线索二叉树进行中序遍历,遍历结果为递增的,将结果存储在list集合中;

2.在主函数中,对list集合进行遍历,首先构成双向链表;

3.将双向链表的首尾连接形成双向循环链表。

 public Node treeToDoublyList(Node root) {
        
        if (root==null){
            return null;
        }
        List<Integer> list = new ArrayList<>();
        inOrderRecur(root,list);
        Node head = new Node(list.get(0));
        Node temp = head;
        for (int i=1;i<list.size();i++){
            Node node = new Node(list.get(i));
            temp.right=node;
            node.left=temp;
            temp=temp.right;
        }
        temp.right=head;
        head.left=temp;
        return head;
    }
    public void inOrderRecur(Node root , List<Integer> list) {
        if (root == null) {
            return;
        }
        inOrderRecur(root.left,list);
        list.add(root.val);
        inOrderRecur(root.right,list);
    }

剑指 Offer 54. 二叉搜索树的第k大节点

题目:

给定一棵二叉搜索树,请找出其中第k大的节点。

题解1:

按照上一题的思路,对线索二叉树进行中序遍历,将遍历结果存储在list集合中,返回list集合中第k大的值即可。

 public int kthLargest(TreeNode root, int k) {
        List<Integer> list = new ArrayList<>();
        inOrderRecur(root,list);
        return list.get(list.size()-k);
    }
    public void inOrderRecur(TreeNode root , List<Integer> list) {
        if (root == null) {
            return;
        }
        inOrderRecur(root.left,list);
        list.add(root.val);
        inOrderRecur(root.right,list);
    }

题解2:

1.对线索二叉树进行遍历,遍历的顺序为先遍历右子树,再遍历根节点,再遍历左子树,遍历结果为递减序列;

2.使用全局变量sum来记录当前递归节点的个数,当sum==k时,表明此时根节点为第k大的值,结束递归返回值即可。

class Solution {
    int k,res,sum=0;
    public int kthLargest(TreeNode root, int k) {
        this.k=k;
        postOrderRecur(root);
        return res;
    }

    public void postOrderRecur(TreeNode root) {
       
        if (root == null) {
            return ;
        }
        postOrderRecur(root.right);
        sum++;//记录此时访问节点的数量
        if (sum == k){
            res = root.val;
            return;
        }
        postOrderRecur(root.left);
    }
}

剑指 Offer 45. 把数组排成最小的数

题目:

输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。

题解:

把数组排成最小的数

两个字符串a和b,如果a+b>b+a,则a应该在b的后面

Arrays.sort()[sort](…/…/java/util/Arrays.html#sort(T[], java.util.Comparator))(T[] a, Comparator<? super T> c)可以自定义一个比较器

    public String minNumber(int[] nums) {

        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }

剑指 Offer 61. 扑克牌中的顺子

题目:

从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。

题解:

集合 Set / 排序,清晰图解

能够连成顺子的两个条件:

  • 数组中无重复数字
  • 最大值和最小值的差值最大为4
    public boolean isStraight(int[] nums) {
        
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        Set<Integer> set = new HashSet<>();//确保没有重复的
        for (int num:nums){
            if(num == 0) continue; // 跳过大小王
            min = Math.min(min,num);
            max = Math.max(max,num);
            if (set.contains(num)){
                return false;
            }
            set.add(num);
        }
        return max-min<5;
    }

剑指 Offer 40. 最小的k个数

题目:

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

题解:

直接sort

  public int[] getLeastNumbers(int[] arr, int k) {
        int[] res = new int[k];
        Arrays.sort(arr);
        for (int i=0;i<k;i++){
            res[i]=arr[i];
        }
        return res;
    }

剑指 Offer 41. 数据流中的中位数

题目:

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

题解:

优先队列 / 堆,清晰图解

1.建立大顶堆和小顶堆:PriorityQueue<>()默认建立小顶堆,PriorityQueue<>((x, y) -> (y - x))建立大顶堆;

2.如果此时A和B两个堆的数量不相等,向B中add,反之向A中add;

3.在向B中add时,有可能此时的num并不属于较小的那一部分,因此需要先向A中add,然后将A的堆顶元素add至B中。

class MedianFinder {
    Queue<Integer> A, B;
    
    public MedianFinder() {
        A = new PriorityQueue<>(); // 小顶堆,保存较大的一半
        B = new PriorityQueue<>((x, y) -> (y - x)); // 实现大顶堆,保存较小的一半
    }
    public void addNum(int num) {
        if(A.size() != B.size()) {
            A.add(num);
            B.add(A.poll());
        } else {
            B.add(num);
            A.add(B.poll());
        }
    }
    public double findMedian() {
        return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;
    }
}

emo了好久,我终于和自己和解了!

以上是关于剑指 offer day15-17的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer打卡目录(Java实现)

《剑指offer》专题—算法训练 day02

《剑指offer》专题—算法训练 day01

《剑指offer》专题—算法训练 day04

《剑指offer》专题—算法训练 day03

剑指offer--Day6