剑指offer自用笔记

1. 题目 :链表中环的入口结点

答题牛客答题链接
思路:
在这里插入图片描述
原理:
在这里插入图片描述
代码:

public class EntryNodeOfRing7 {
    public static void main(String[] args) {
        ListNode r1=new ListNode(1);
        ListNode r2=new ListNode(2);
        ListNode r3=new ListNode(3);
        ListNode r4=new ListNode(4);
        ListNode r5=new ListNode(5);

        r1.next=r2;
        r2.next=r3;
        r3.next=r4;
        r4.next=r5;
        r5.next=r3;

        ListNode ListNode = EntryNodeOfLoop(r1);
        System.out.println(ListNode.val);
    }

    public static ListNode EntryNodeOfLoop(ListNode pHead) {
        if (pHead==null){return null;}
        ListNode fast=pHead;
        ListNode slow=pHead;
        while (fast!=null){  //判断有环无环,有环才一直循环
            fast=fast.next.next;
            slow=slow.next;
            if (fast==slow){   //第一次相遇
                fast=pHead;
                while (fast!=slow && fast!=null){   //让其第二次相遇
                    fast=fast.next;
                    slow=slow.next;
                }
                return fast;
            }
        }
        return null;
    }
}

2.题目:整数中1出现的次数(从1到n整数中1出现的次数)

描述: 输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数
例如,1~13中包含1的数字有1、10、11、12、13因此共出现6次
**思路:*分三种情况,某个位置的数比1大,比1小,或者等于1。
1. 比1大 那么有(a+1)base种情况
2. 等于1 那么有(a
base)+1
(b+1)种情况
3. 比1小 那么有a*base种情况
在这里插入图片描述
代码:

public class NumberOfTimes1InInteger12 {
    public static void main(String[] args) {
        int i = NumberOf1Between1AndN_Solution(13);
        System.out.println(i);
    }

    public static int NumberOf1Between1AndN_Solution(int n) {
        int base=1;//起始位是个位
        int count=0;

        while (base<=n){
            int a=n/base;
            int b=n%base;//b要的是余数
            int cur=a%10;//cur要的是商再取余数
            a=a/10;//a要的是商
            if(cur>1){
                count+=(a+1)*base;
            }else if (cur==1){
                count+=a*base+b+1;
            }else {
                count+=a*base;
            }

            base*=10;
        }
        return count;
    }
}

顺便把树的类也写一下

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

3. 题目:树的子结构

**描述:**输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
在这里插入图片描述
在这里插入图片描述
代码:

public class SubstructuresOfTrees3 {
    public static void main(String[] args) {
        TreeNode r1=new TreeNode(2);
        TreeNode r2=new TreeNode(5);
        TreeNode r3=new TreeNode(6);
        TreeNode r4=new TreeNode(3);
        TreeNode r5=new TreeNode(4);
        TreeNode r6=new TreeNode(1);
        TreeNode r7=new TreeNode(2);
        r1.left=r2;r1.right=r3;
        r2.left=r4;r2.right=r5;
        r3.left=r6;r3.right=r7;

        TreeNode r10=new TreeNode(5);
        TreeNode r11=new TreeNode(3);
        TreeNode r12=new TreeNode(4);
        r10.left=r11; r10.right=r12;

        boolean b = HasSubtree(r1, r10);
        System.out.println(b);
    }

    public static boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if (root1==null || root2==null){
            return false;
        }

        //递归方式,不管根节点树,左子树还是右子树有一个满足条件即可
        return helper(root1,root2) || HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);

    }

    private static boolean helper(TreeNode root1,TreeNode root2){
        if (root2==null) return true;//递归中止条件
        if (root1==null) return false;//root2不是空,而root1已经是空,说明结构不同

        return root1.val==root2.val && helper(root1.left,root2.left) && helper(root1.right,root2.right);
    }
}

4.题目:二叉树的镜像

描述操作给定的二叉树,将其变换为源二叉树的镜像。

在这里插入图片描述
在这里插入图片描述
代码:

public class ImageOfBinaryTree4 {
    public static void main(String[] args) {
        TreeNode r1=new TreeNode(2);
        TreeNode r2=new TreeNode(5);
        TreeNode r3=new TreeNode(6);
        TreeNode r4=new TreeNode(3);
        TreeNode r5=new TreeNode(4);
        TreeNode r6=new TreeNode(1);
        TreeNode r7=new TreeNode(2);
        r1.left=r2;r1.right=r3;
        r2.left=r4;r2.right=r5;
        r3.left=r6;r3.right=r7;

        TreeNode mirror = Mirror(r1);
        bli(mirror);
    }

    public static TreeNode Mirror (TreeNode pRoot) {
        if (pRoot==null){
            return pRoot;
        }

        //获取反转过后的子树
        TreeNode l=Mirror(pRoot.left);//已经反转过的左子树
        TreeNode r=Mirror(pRoot.right);//已经反转过的右子树

        //左右互换
        pRoot.left=r;
        pRoot.right=l;
        return pRoot;
    }

    //前序遍历,中序和后序就是调换下位置就行
    public static void bli(TreeNode tree){
        if (tree==null){
            return ;
        }
        System.out.println(tree.val);
        bli(tree.left);
        bli(tree.right);

    }
}

5.题目:二叉搜索树的后序遍历序列

描述输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。(ps:我们约定空树不是二叉搜素树)。
什么是二叉搜索树,什么是后序遍历弄清楚。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
代码:

public class BinarySearchTreePostOrder6 {
    public static void main(String[] args) {
        int[] arr={1,3,2,6,5};
        boolean b = VerifySquenceOfBST(arr);
        System.out.println(b);

    }

    public static boolean VerifySquenceOfBST(int [] sequence) {
        //根据后序遍历的特征,数组最后一个元素必定是当前数的根
        //则从数组第一个元素开始寻找比该根大的元素,判断是否左半边大于他,右半边小于他
        //然后递归判断下一个数组,直到数组长度为1才返回
        if(sequence.length == 0)
            return false;
        return judge(sequence,0,sequence.length-1);
    }

    //验证根节点左子树是否小于根节点,右子树是否都大于根节点
    private static boolean judge(int[] sequence,int start,int end){
        if (start >= end) return true;//终止条件
        int head=sequence[end];
        int count=start;
        while (sequence[count]<head) count++;
        for (int i = count; i < end; i++) {
            if (sequence[i]<head) return false;
        }
        return judge(sequence,start,count-1) && judge(sequence,count,end - 1);
    }
}

6.题目:二叉树中和为某一值的路径

描述输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

在这里插入图片描述

在这里插入图片描述
代码:

public class BinaryTreePathWithaValue7 {
    private static ArrayList<Integer> list1=new ArrayList<Integer>();
    private static ArrayList<ArrayList<Integer>> list2=new ArrayList<ArrayList<Integer>>();

    public static void main(String[] args) {
        TreeNode r1=new TreeNode(2);
        TreeNode r2=new TreeNode(5);
        TreeNode r3=new TreeNode(6);
        TreeNode r4=new TreeNode(3);
        TreeNode r5=new TreeNode(4);
        TreeNode r6=new TreeNode(1);
        TreeNode r7=new TreeNode(2);
        r1.left=r2;r1.right=r3;
        r2.left=r4;r2.right=r5;
        r3.left=r6;r3.right=r7;

        ArrayList<ArrayList<Integer>> arrayLists = FindPath(r1, 9);
        System.out.println(arrayLists);
    }
    public static ArrayList<ArrayList<Integer>> FindPath(TreeNode root, int target) {
        dynamic(root,target);
        return list2;
    }

    public static void dynamic(TreeNode root, int target){
        if (root==null) return;
        list1.add(root.val);  //获取根节点,存入动态数组
        target=target-root.val;  //重新计算和

        /*这里为什么是list2.add(new ArrayList<>(list1)),而不是list2.add(list1)
        *因为list1是动态变化的,而且list1对象与传入list2中的对象是同一个,这样list1变化,
        * 会导致list2也跟着变化
         */
        if (target==0 && root.left==null && root.right==null) list2.add(new ArrayList<>(list1));//如果强调最后的节点再没有其它叶子节点,用此法
        //if (target==0) list2.add(new ArrayList<>(list1));  //如果不强调是完整的一个分支,可用此法

        dynamic(root.left,target);
        dynamic(root.right,target);
        list1.remove(list1.size()-1);

    }
}

7.题目:二叉搜索树与双向链表

描述输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构

在这里插入图片描述

public class BinarySearchTreeAndLinkedList8 {
    static TreeNode tmp=null,head;
    public static void main(String[] args) {
        TreeNode r1=new TreeNode(2);
        TreeNode r2=new TreeNode(5);
        TreeNode r3=new TreeNode(6);
        TreeNode r4=new TreeNode(3);
        TreeNode r5=new TreeNode(4);
        TreeNode r6=new TreeNode(1);
        TreeNode r7=new TreeNode(2);
        r1.left=r2;r1.right=r3;
        r2.left=r4;r2.right=r5;
        r3.left=r6;r3.right=r7;

        TreeNode convert = Convert(r1);
        System.out.println(convert.val);
    }

    public static TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree==null) return null;
        linked(pRootOfTree);
        //下面两行代码是让头节点指向尾节点,尾节点指向头节点,看题目要求是否使用
        /*tail.right=head;
        head.left=tail;*/
        return head;
    }

    //用于递归转换的子树
    public static void linked(TreeNode pRootOfTree){
        if (pRootOfTree==null) return ;  //
        linked(pRootOfTree.left);//递归转换左子树
        if (tail==null){ //此时还没有开始转换,那么当前节点就是要返回的头节点
            head=pRootOfTree;
        }else {  //把当前节点和转换好后的链表进行链接
            tail.right=pRootOfTree;//链表尾节点的右指针指向当前节点
            pRootOfTree.left=tail;//当前节点的左指针指向链表的尾节点
        }
        tail=pRootOfTree; //当前节点赋值给链表的尾节点
        linked(pRootOfTree.right);//递归转换右子树

    }
}

8.题目:最小的K个数

描述给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。如果K>数组的长度,那么返回一个空的数组

/*
最小的K个数

给定一个数组,找出其中最小的K个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
如果K>数组的长度,那么返回一个空的数组

思路:最大堆处理,因为最大堆的特点是根节点的值永远是最大的,那么我们先建立一个最大堆,里面存入k个值,然后再拿数组里面剩余的数,每次都跟最大堆的最大值进行比较,大于最大堆的最大值就不用处理,小于最大堆的值,删除最大堆的值,填入该值。
 */
public class MinimumNumberOfK15 {
    public static void main(String[] args) {
        int[] arr={4,5,1,6,2,7,3,8};
        ArrayList<Integer> integers = GetLeastNumbers_Solution(arr, 2);
        System.out.println(integers);

    }

    public static ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if (input.length<k || k<1) return new ArrayList<>();

        //建立最大堆
        PriorityQueue<Integer> pq = new PriorityQueue<>(k, new Comparator<Integer>(){
            public int compare(Integer o1, Integer o2){
                return o2 - o1;
            }
        });

        //往最大堆里存k个数
        for (int i = 0; i < k; i++) {
            pq.add(input[i]);
        }

        //移除数组最大值,填入最小值
        for (int i = k; i < input.length; i++) {
            if (input[i]< pq.peek()){
                pq.poll();
                pq.add(input[i]);
            }
        }
        return new ArrayList<>(pq);
    }
}

9.题目:数据流中的中位数

描述如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

三种方法:
在这里插入图片描述
这里我们用第三种方法,很巧妙
在这里插入图片描述
在这里插入图片描述

package Number;

import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Queue;
/**
 * 数据流中的中位数
 *
 * 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。
 * 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,
 * 使用GetMedian()方法获取当前读取数据的中位数。
 */
public class MedianInDataStream16 {
    static Queue<Integer> min=new PriorityQueue<>();//默认最小堆;
    static Queue<Integer> max=new PriorityQueue<>(2,new Comparator<Integer>(){ //实现最大堆,栈顶存放的是最大值
        public int compare(Integer o1, Integer o2){
            return o2 - o1;
        }
    });
//        );

    public static void main(String[] args) {
        Insert(2);
        Insert(0);
        Insert(3);
        Insert(4);
        Insert(1);
        Double aDouble = GetMedian();
        System.out.println(aDouble);
    }
    public static void Insert(Integer num) {
        max.add(num);
        min.add(max.poll());
        //保持max堆的个数,大于等于min堆个数
        if (max.size()< min.size()){
            max.add(min.poll());
        }
    }

    public static Double GetMedian() {
        if (max.size() > min.size()) {
             return (double)max.peek();
        }else {
            return (max.peek()+ min.peek())/2.0;
        }
    }
}

10.题目:二叉树的下一个结点

描述给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值