LeetCode常见题目以及解法(由于是是自己写的,有个别题目只写了思路,没写过程,因为思路写了,应该没啥问题的,还有就是基本没有注释)

package com.mzz;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.Stack;
import java.util.concurrent.LinkedBlockingDeque;

import javax.swing.text.AbstractDocument.BranchElement;

public class LeetCode {

    /*
        例题:给定一个长度为n的数组,其中只有一个数字出现的次数大于等于n/2次,求出该数字。
        解:使用投票法:通过维护一个候选众数candidate,一般选择第一个元素即可,和它出现的次数counts并初始化为1,然后从第二个元素开始遍历数组,如果数组中
        元素值与候选值相同,就将counts++,否则counts--,接下来判断counts如果等于0,就将候选众数设置为下一个元素,并且重置counts为1,遍历完毕,候选众数就是最后的结果。
    */
    public static int majorityElement(int[] nums){
        int temp=nums[0];
        int counts=1;
        for(int i=1;i<nums.length;i++){
            if(nums[i]!=temp){
                counts--;
            }else{
                counts++;
            }
            if(counts==0){
                counts=1;
                if(i<nums.length-1){
                    temp=nums[++i];
                }
            }
        }
        return temp;
    }
    /*
        例题:给定一个n*m的数组,每行元素和每列元素保证递增,试判断某个数子是否在数组中。
        解:使用一个指针,该指针从数组的右上角向最下角运行,如果数组元素大于目标元素就向左移动,如果数组元素小于目标元素,就向下移动,如果等于就返回true。如果到达边界依然没有,就返回false。
    */
    public static boolean searchNum(int[][] nums,int target){
        int row=0;
        int col=nums[0].length-1;
        while(row<nums.length&&col>=0){
            if(nums[row][col]==target) return true;
            if(nums[row][col]>target) row++;
            else col--;
        }
        return false;
    }
    /**
        例题:有两个有序数组,将其合并为一个有序数组
        解:如果题目中是将一个数组合并到另一个数组时,可以从合并数组最后一个元素往前添加
     */
    public static void mergeArray(int[] nums1,int[] nums2, int[] nums){
        int index1=0;
        int index2=0;
        int index=0;
        while(index1<nums1.length&&index2<nums2.length){
            if(nums1[index1]>nums2[index2]){
                nums[index++]=nums2[index2++];
            }else{
                nums[index++]=nums1[index1++];
            }
        }
        while(index1<nums1.length)nums[index++]=nums1[index1++];
        while(index2<nums2.length)nums[index++]=nums2[index2++];
    }
    /**
     * 加油站:在一条环路上有N个加油站,其中在第i个加油站加汽油gas[i]升,你有一辆容量无限的汽车,
     * 从第i个加油站开往第i+1个加油站消耗cost[i]升,清从一个加油站出发,开始时,油箱为空。如果你
     * 可以绕环路一周,则返回编号,否则返回-1.
     * 说明:如果题目有解,答案唯一。
     *      输入数组均非空,长度相同。
     *      输入数组中元素均为非负
     *  解:如果total_gas<0一定不会走完环路,否则一定可以的。
     */
    public static int gasStation(int[] gas,int[] cost){
        int total_gas=0;
        int current_gas=0;
        int resp=0;
        for(int i=0;i<gas.length;i++){
            total_gas+=(gas[i]-cost[i]);
            current_gas+=(gas[i]-cost[i]);
            if(current_gas<0) {
                current_gas=0;
                resp=i;
            }
            
        }
        if(total_gas<0)return -1;
        else return resp+1;

    }
    /**
    * LRU缓存机制
    * 设计和实现一个LUR(最近最少使用)缓存机制,支持的操作有获取数据get和写入数据put。
    * 获取数据get(key),如果关键字在缓存中,就获取关键字的值,总是为正,否则返回-1.写入
    * 数据put(key,value),如果关键字存在,就变更其中数据,如果关键字不存在,就插入其中。
    * 当缓存到达上限时,再写入之前删除最久未使用的数据值,从而为新数据腾出空间。
    */
    class LRUCache{
        HashMap<Integer,Node> map=new HashMap<>();
        int capacity;
        int size=0;
        Node head;
        Node tail;
        public LRUCache(int capacity){
            head=new Node(-1,-1);
            tail=new Node(-1,-1);
            head.next=tail;
            head.pre=null;
            tail.pre=head;
            tail.next=null;
            this.capacity=capacity;
        }
    
        public int get(int key){
            if(map.containsKey(key)){
                Node node=map.get(key);
                node.pre.next=node.next;
                node.next.pre=node.pre;
                moveToHead(node);
                return map.get(key).value;
            }
            else return -1;
        }
        public void put(int key,int value){
            if(!map.containsKey(key)){//缓存中没有但已经满了
                Node node=new Node(value, key);
                map.put(key, node);
                moveToHead(node);
                size++;
                if(size-capacity==1){
                    size--;
                    node=tail.pre;
                    tail.pre=node.pre;
                    node.pre.next=tail;
                    map.remove(node.key);
                }
            }else{//缓存中有
                Node node=map.get(key);
                node.value=value;
                node.pre.next=node.next;
                node.next.pre=node.pre;
                moveToHead(node); 
            }
    
        }
        public void moveToHead(Node node) {
            node.next=head.next;
            head.next.pre=node;
            head.next=node;
            node.pre=head;     
        }
        class Node{
            int value;
            int key;
            Node pre;
            Node next;
            public Node(int value,int key){
                this.value=value;
                this.key=key;
            }
        }
    }
    /**
     *  快乐数:快乐数定义为对于一个整数,每次将该数替换为它每个位置上的数子的平方和,
     *  然后重复这个过程,直到这个数变为1,也可以无线循环但始终不到1,如果为1,那么就是快乐数
     *  解:第一种使用HashSet判断是否有循环
     *      第二种使用快慢指针来判断隐形的链表是否有环。
     *      本题使用快慢指针
     */
    public static boolean happyNum(int num){
        int fast=num;
        int slow=num;
        while(fast!=1){
            fast=nextNum(nextNum(fast));
            slow=nextNum(slow);
            if(fast==slow)return false;
        }
        return true;
    }
    public static int nextNum(int num){
        int resp=0;
        while(num>0){
            int remain=num%10;
            resp+=(remain*remain);
            num/=10;
        }
        return resp;
    }
    /**
     * 生命游戏:给定一个包含m*n个格子的面板,每个格子都可以看作成一个细胞,每个细胞都具有一个初始状态:
     * 1即为活细胞,0为死细胞。每个细胞与八个相邻位置的细胞都遵循以下生存规律:
     *  1:如果活细胞周围八个位置的活细胞少于2个,那么该位置的细胞死亡。
     *  2:如果活细胞周围八个位置的活细胞有2个或者3个,那么该细胞任然存活。
     *  3:如果活细胞周围八个位置的活细胞有3个以上,那么该位置细胞死亡。
     *  4:如果死细胞周围八个位置正好有3个活细胞,那么该位置细胞复活。
     * 根据当前状态,写一个函数来计算面板上所有细胞下一个状态,下一个状态时通过上个规则同时应用于当前状态
     * 形成的,其中死亡与出生复活同时发生。
     * 解:遍历面板,如果活细胞死亡,则使用Integer.MIN标记表示下一状态为死,如果死细胞复活就用Integer.MAX
     * 标记表示下一状态为活。在判断周围细胞状态时,Integer.MIN表示细胞当前状态为活,Integer.MAX表示细胞当
     * 前状态为死。遍历完毕应该再遍历一次,将下一标记了状态的细胞使用0,1替换。
     */
    public static void lifeGame(int[][] board){
        int rows=board.length;
        int cols=board[0].length;
        
        for(int row=0;row<rows;row++){
            for(int col=0;col<cols;col++){
                int lives=0;
                if(row>0){
                    if(board[row-1][col]==1||board[row-1][col]==Integer.MIN_VALUE) lives++;
                    if(col>0){
                        if(board[row][col-1]==1||board[row][col-1]==Integer.MIN_VALUE) lives++; 
                        if(board[row-1][col-1]==1||board[row-1][col-1]==Integer.MIN_VALUE) lives++;
                    }
                    if(col<cols-1){
                        if(board[row][col+1]==1||board[row][col+1]==Integer.MIN_VALUE) lives++;
                        if(board[row-1][col+1]==1||board[row-1][col+1]==Integer.MIN_VALUE) lives++;
                    }


                }
                if(row<rows-1){
                    if(board[row+1][col]==1||board[row+1][col]==Integer.MIN_VALUE) lives++;
                    if(col>0){
                        if(board[row+1][col-1]==1||board[row+1][col-1]==Integer.MIN_VALUE) lives++;
                    }
                    if(col<cols-1){
                        if(board[row+1][col+1]==1||board[row+1][col+1]==Integer.MIN_VALUE) lives++;
                    }
                }
                if(board[row][col]==1||board[row][col]==Integer.MIN_VALUE)
                {
                    if(lives!=2&&lives!=3)board[row][col]=Integer.MIN_VALUE;
                    
                }
                else{
                    if(lives==3) board[row][col]=Integer.MAX_VALUE;
                }
            }
        }
        for(int row=0;row<rows;row++){
            for(int col=0;col<cols;col++){
                if(board[row][col]==Integer.MAX_VALUE) board[row][col]=1;
                if(board[row][col]==Integer.MIN_VALUE) board[row][col]=0;
                System.out.print(board[row][col]+" ");
            }
            System.out.println();
        }

    }
    /**
     * 两整数之和:不使用+、-计算两整数a、b之和。
     * 本题解对负数有问题
     */
    public static int sum(int a,int b){
        int temp1=a^b;
        int temp2=a&b;
        temp2<<=1;
        while(temp2>0){
            a=temp1;
            b=temp2;
            temp1=a^b;
            temp2=a&b;  
            temp2<<=1;     
        }
        return temp1;
    }
    /**
     * 乘积最大子序列:给定一个数组nums,找出数组中乘积最大的连续子数组,该子数组中至少包含一个元素,并返回
     * 最大乘积。
     * 解:遍历数组时,如果当前元素是整数,我们希望前面一段的乘积更加正,如果是个负数,我们希望前面一段乘积
     * 更加负。即状态转移为:
     *  f_max=max{f_max*nums[i-1],f_min*nums[i-1],nums[i-1]};
     *  f_min=min{f_max*nums[i-1],f_min*nums[i-1],nums[i-1]};
     */
    public static int maxProduct(int[] nums){
        int min=nums[0];
        int max=nums[0];
        int resp=0;
        for(int i=1;i<nums.length;i++){
            int tempMax=Math.max(max*nums[i], min*nums[i]);
            tempMax=Math.max(tempMax,nums[i]);  
            int tempMin=Math.min(max*nums[i], min*nums[i]);
            tempMin=Math.min(tempMin,nums[i]); 
            max=tempMax;
            min=tempMin;
            resp=Math.max(max, resp);  
        }
        return resp;
    }
    /**
     * 求众数:给定一个大小为n的数组,找到多数元素,多数元素指的是数组中出现次数大于[n/2]的元素,
     * 数组非空,并且总是存在多数元素。
     * 解:使用投票法
     */
    public static int searchMajorityElement(int[] nums){
        int candidate=nums[0];
        int counts=1;
        for(int i=1;i<nums.length;i++){
            if(candidate!=nums[i]){
                counts--;
            }else{
                counts++;
            }
            if(counts==0){
	            if(i<nums.length-1)candidate=nums[++i];
                counts=1;
            }
        }
        return candidate;
    }
    /**
     * 旋转数组:给定一个数组,将数组中的元素向右移动k个位置,其中k非负
     * 解1:使用环形替换法
     * 解2:先反转全部,然后反转前k个,再反转后N-k个元素
     */
    public static void roastArray(int[] nums,int k){
        k=k%nums.length;
        int counts=0;
        int index=0;
        int temp1=nums[index];
        while(counts<nums.length){
            int temp2=nums[(index+k)%nums.length];
            nums[(index+k)%nums.length]=temp1;
            index=(index+k)%nums.length;
            temp1=temp2;
            counts++;
        }

    }
    /**
     * 存在重复元素:给定一个整数数组,判断是否存在重复元素,如果任意一个元素在数组中出现至少两次,
     * 则返回true,所有元素都不相同,则返回false。
     * 解1:使用堆排序,然后比较相邻的元素是否有一样的
     * 解2:使用HashSet,如果在添加过程中有存在的说明有重复的
     * 没有即快又省空间的算法
     */
    /**
     * 移动零:给定一个数组,将数组中的所有0都移动到数组末尾,同时保持非零元素的相对顺序
     * 解:双指针,慢指针指向第一个0元素,快指针从慢指针后面第一个非0元素开始,快指针遇到非0元素,
     * 就将指向的元素赋值给慢指针指向的位置,然后慢指针前进一个位置。直到快指针遍历完毕。最后再从
     * 慢指针位置开始遍历,将所经过位置都赋值为0.
     */
    public static void moveZero(int[] nums){
        int zeroPtr=0;
        while(zeroPtr<nums.length&&nums[zeroPtr]!=0){
            zeroPtr++;
        }
        int fast=zeroPtr+1;
        while(fast<nums.length){
            if(nums[fast]!=0){
                nums[zeroPtr]=nums[fast];
                zeroPtr++;               
            }
            fast++; 
        }
        while(zeroPtr<nums.length){
            nums[zeroPtr++]=0;
        }
    }
    /**
     * 打乱数组:打乱一个没有重复的数组,并返回打乱后的数组,并且有重置操作。
     * 解:使用Fisher-Yates洗牌算法:遍历数组元素,每次迭代时,随机生成从当前下标到末尾下标的一个数,
     *     然后交换当前元素和随机数位置上的元素。
     */
    public static void shuffle(int[] nums){
        int len=nums.length;
        Random random=new Random();
        for(int i=0;i<len;i++){
            int n=len-i;
            int pos=random.nextInt(n)+i;
            int temp=nums[pos];
            nums[pos]=nums[i];
            nums[i]=temp;
        }
    }
    /**
     * 两个数组的交集II:给定两个数组,编写一个函数来计算它们的交集,输出结果的顺序不考虑,
     * 结果的每个元素出现的次数为原来两个数组中该元素同时出现次数中的较小的一个次数。
     * 解1:使用哈希表存储元素比较少的数组中每个元素出现的次数,然后遍历另外一个数组,如果
     * 哈希表中存在该元素,则向结果添加该元素,并将该元素的次数减一,如果次数为0,则从哈希
     * 表中移除该元素。
     * 解2:先排序,然后使用两个指针遍历两个数组,初始时指向头元素,然后指向比较小元素的指针
     * 应向后移动,直到遇到第一个与另一个指针指向元素值相等,这时,向结果中添加该元素,如果
     * 遇到第一个大于另一个元素的元素,应该更换角色。
     */
    public static int[] interSet(int[] nums1,int[] nums2){
        ArrayList<Integer> list=new ArrayList<>();
        HashMap<Integer,Integer> hashMap=new HashMap<>();
        for(int num:nums1){
            if(hashMap.containsKey(num)){
                hashMap.put(num, hashMap.get(num)+1);
            }else{
                hashMap.put(num, 1);
            }
        }
        for(int num:nums2){
            if(hashMap.containsKey(num)){
                list.add(num);
                if(hashMap.get(num)==1) hashMap.remove(num);
                else hashMap.put(num, hashMap.get(num)-1);
            }
        }
        int[] resp=new int[list.size()];
        for(int i=0;i<list.size();i++){
            resp[i]=list.get(i);
        }
        return resp;
    }
    /**
     * 递增的三元子序列:给定一个未排序的数组,判断这个数组中是否存在长度为3的递增子序列。
     * 要求算法时间复杂度为O(N),空间复杂度为O(1)。
     * 解:维护一个最小元素和次小元素
     */
    public static boolean tripleSubSeque(int[] nums){
        int min=Integer.MAX_VALUE;
        int subMin=Integer.MAX_VALUE;
        for(int num:nums){
            if(num<=min) min=num;
            else if(num<=subMin) subMin=num;
            else return true;
        }
        return false;


    }
    /**
     * 除自身以外数组的乘积:给定一个长度为n的整数数组nums,返回一个数组output,其中output[i]等与nums中除了nums[i]以外所有元素的乘积
     */
    public static int[] productExceptSelf(int[] nums){
        int[] output=new int[nums.length];
        output[0]=nums[0];
        for(int i=1;i<nums.length;i++){
            output[i]=nums[i]*output[i-1];
        }
        output[nums.length-1]=output[nums.length-2];
        int temp=nums[nums.length-1];
        for(int i=nums.length-2;i>0;i--){
            output[i]=output[i-1]*temp;
            temp*=nums[i];
        }
        output[0]=temp;
        return output;
    }
    /**
     * 赋值带随机指针的链表:给定一个链表,每个节点包含一个额外增加的随机指针,
     * 该指针可以指向链表中的任何节点或者空节点,求返回这个链表的深拷贝。
     * 解:先将新链表实现,不管随机指针,实现过程中,将原节点与新节点按照键值对存储在哈希表中
     *     然后再次遍历链表,将随机指针加进去
     */
    public static NodeWithRandomPtr deepCopyLinkList(NodeWithRandomPtr root){
        if(root==null)return null;
        LeetCode leetCode=new LeetCode();
        HashMap<NodeWithRandomPtr,NodeWithRandomPtr> hashMap=new HashMap<>();
        LeetCode.NodeWithRandomPtr head=leetCode.new NodeWithRandomPtr(root.value);
        hashMap.put(root, head);
        NodeWithRandomPtr sour=root;
        NodeWithRandomPtr dest=head;
        while(sour.next!=null){
            NodeWithRandomPtr node=new LeetCode().new NodeWithRandomPtr(sour.next.value);
            dest.next=node;
            sour=sour.next;
            dest=dest.next;
            hashMap.put(sour, dest); 
        }
        sour=root;
        dest=head;
        while(sour!=null){
            if(sour.random_index!=null){
                dest.random_index=hashMap.get(sour.random_index);
                System.out.print(dest.random_index.value);
            }
            sour=sour.next;
            dest=dest.next;
        }


        return head;
    }
    class NodeWithRandomPtr{
        int value;
        NodeWithRandomPtr random_index;
        NodeWithRandomPtr next;
        public NodeWithRandomPtr(int value){
            this.value=value;
        }
    }
    /**
     * 环形链表:给定链表,判断链表是否有环
     */
    public static boolean hasCycle(LinkNode root){
        if(root==null||root.next==null)return false;
        LinkNode fast=root;
        LinkNode slow=root;
        while(fast!=slow){
            if(fast==null||fast.next==null) return false;
            fast=fast.next.next;
            slow=slow.next;
        }
        return true;

    }
    class LinkNode{
        int value;
        LinkNode next;
    }
    /**
     * 排序链表:在O(Nlog(N))的时间复杂度和O(1)的空间复杂度下对链表排序
     * 解:使用归并排序从低至顶合并
     *  intv=1:4     3    2     6    5     7    1
     *  intv=2:  3 4        2 6        5 7        1
     *  intv=4:     2 3 4 6               1 5 7
     *  intv=8:             1 2 3 4 5 6 7
     * 首先统计链表长度len,最外循环中通过intv<len作为此循环的条件。
     * 外循环内每次从首节点开始,合并左右两部分。
     */
    public static LeetCode.SortLinkNode sortLinkList(SortLinkNode root){
        LeetCode leetCode=new LeetCode();
        LeetCode.SortLinkNode sortLinkNode=leetCode.new SortLinkNode(0);
        sortLinkNode.next=root;
        int len=0;
        SortLinkNode tNode=root;
        while(tNode!=null){
            tNode=tNode.next;
            len++;
        }
        int intv=1;
        while(intv<len){
            SortLinkNode left=sortLinkNode;
            SortLinkNode right=sortLinkNode;
            while(right.next!=null){
                int pos=0;
                while(right.next!=null&&pos<intv){
                    right=right.next;
                    pos++;
                }
                int leftCount=0;
                int rightCount=0;
                while(leftCount<intv&&rightCount<intv&&right.next!=null){
                    if(left.next.value<=right.next.value){
                        left=left.next;
                        leftCount++;
                    }else{
                        SortLinkNode temp=right.next;
                        right.next=temp.next;
                        temp.next=left.next;
                        left.next=temp;
                        left=left.next;
                        rightCount++;
                    }
                }
                while(right.next!=null&&rightCount<intv) {
                    right=right.next;
                    rightCount++;
                }
                left=right;
            }
            intv*=2;
        }
        return sortLinkNode.next;


    }
    class SortLinkNode{
        int value;
        SortLinkNode next;
        public SortLinkNode(int value){
            this.value=value;
        }
    }
    /**
     * 链表相交:找到两个单链表相交的起点。
     * 如:
     *      1->2->3
     *              ->7->8->null
     *      4->5->6
     * 那么7就是相交的起始节点。
     */
    public static InterLinkNode getInterNode(InterLinkNode link1,InterLinkNode link2){
        int len1=0;
        int len2=0;
        InterLinkNode node=link1;
        while(node!=null){
            len1++;
            node=node.next;
        }
        node=link2;
        while(node!=null){
            len2++;
            node=node.next;
        }
        if(len1>len2){
            int counts=len1-len2;
            while(counts>0){
                link1=link1.next;
                counts--;
            }
        }else{
            int counts=len2-len1;
            while(counts>0){
                link2=link2.next;
                counts--;
            }   
        }
        while(link1!=null){
            if(link1==link2)return link1;
            link1=link1.next;
            link2=link2.next;
        }
        return null;
    }
    class InterLinkNode{
        int value;
        InterLinkNode next;
        public InterLinkNode(int value){
            this.value=value;
        }
    }
    /**
     * 回文链表:判断一个链表是否是回文链表,需要满足时间复杂度O(N)和空间复杂度O(1)。
     * 解:为了实现复杂度要求,可以通过改变链表结构,比较完,再恢复链表结构。即首先将链表前
     * 半段或者后半段反转,然后比较,比较完恢复链表,再返回结果即可。
     */
    public static boolean isHuiwenLink(HuiwenLinkNode root){
        if(root==null||root.next==null)return true;
        HuiwenLinkNode node=root;
        int len=0;
        while(node!=null){
            node=node.next;
            len++;
        }
        node=root;
        int i=0;
        while(i<len/2){
            node=node.next;
            i++;
        }
        HuiwenLinkNode leftStart=reverseLink(root, len/2);
        HuiwenLinkNode left=leftStart;
        HuiwenLinkNode right=node;
        if(len%2==1)right=node.next;
        boolean resp=true;
        while(right!=null){
            if(right.value!=left.value) {
                resp=false;
                break;
            }
            right=right.next;
            left=left.next;
        }
        reverseLink(leftStart, len/2);
        leftStart.next=node;
        return resp;


       
    }
    public static HuiwenLinkNode reverseLink(HuiwenLinkNode root,int len){
        LeetCode.HuiwenLinkNode left=null;
        LeetCode.HuiwenLinkNode mid=root;
        LeetCode.HuiwenLinkNode right=null;
        int i=0;
        while(i<len){
            right=mid.next;
            mid.next=left;
            left=mid;
            mid=right;
            i++;
        }
        return left;
    }
    class HuiwenLinkNode{
        int value;
        HuiwenLinkNode next;
        public HuiwenLinkNode(int value){
            this.value=value;
        }
    }
    /**
     * 删除链表节点:编写函数,使其可以删除链表中给定的非末尾节点,传入的参数是首节点和要删除的节点值,所有的节点值都唯一。
     * 由于没有说要返回删除后链表的首节点,所以如果删除的是首节点,那么就会有问题了。所以假设不会删除首节点。
     */
    public static void deleteNode(DeleteLinkNode root, int value) {
        while(true){
            if(root.next.value==value){
                root.next=root.next.next;
                return;
            }
            root=root.next;
        }
    }
    class DeleteLinkNode{
        int value;
        DeleteLinkNode next;
        public DeleteLinkNode (int value) {
            this.value=value;
            
        }
    }
    /**
     * 奇偶链表:给定一个单链表,把所有的奇数节点和偶数节点分别排在一起,奇偶性指
     * 的是节点编号的奇偶性,而不是节点值得奇偶性。第一个节点是奇数节点。要求空间复杂度为O(1),时间复杂度为
     * O(N)。
     */
    public static OddEvenLinkNode oddEvenLink(OddEvenLinkNode root){
        if(root==null||root.next==null)return root;
        OddEvenLinkNode left=root;
        OddEvenLinkNode right=root.next;
        OddEvenLinkNode rightStart=right;
        OddEvenLinkNode node=root.next.next;
        int i=3;
        while(node!=null){
            if(i%2==1){
                left.next=node;
                left=left.next;
                System.out.println("left:"+node.value);
            }else{
                right.next=node;
                System.out.println("right:"+node.value);
                right=right.next;
            }
            i++;
            node=node.next;
            
        }
        left.next=rightStart;
        right.next=null;
        return root;

    }
    class OddEvenLinkNode{
        int value;
        OddEvenLinkNode next;
        public OddEvenLinkNode(int value){
            this.value=value;
        }
    }
    /**
     * 最小堆:设计一个支持push,pop,top操作,并且在常熟时间内检索到的最小元素的栈
     *  push:将元素推入栈中
     *  pop:删除栈顶元素
     *  top:获取栈顶元素
     *  getMin():检索栈中的最小元素
     */
    class MinStack{
        Stack<Integer> stack=new Stack<>();
        Stack<Integer> minsStack=new Stack<>();
        public void push(int item){
            stack.push(item);
            if(minsStack.isEmpty()) {minsStack.push(item);return;}
            minsStack.push(Math.min(item, minsStack.peek()));
            
        }
        public int pop(){
            minsStack.pop();
            return stack.pop();
        }
        public int top(){
            return stack.peek();
        }
        public int getMin(){
            return minsStack.peek();
        }

    }
    /**
     * 数组中的第K个最大元素:在未排序的数组中找到第K个最大的元素。
     * 解:使用堆排序
     */
    public static int  findKthLargest(int[] nums,int k){
        for(int i=nums.length/2-1;i>=0;i--){//从第一个非叶子节点开始,向首元素前进,构建大顶堆
            adjustHeap(nums, i, nums.length);
        }
        for(int j=nums.length-1;j>=nums.length-k;j--){//交换元素值
            int temp=nums[j];
            nums[j]=nums[0];
            nums[0]=temp;
            adjustHeap(nums, 0, j);
        }
        return nums[nums.length-k];
    }
    public static void adjustHeap(int[] nums, int i,int length){
        int temp=nums[i];
        for(int j=2*i+1;j<length;j=2*j+1){
            if(j+1<length&&nums[j]<nums[j+1])//如果有左右子节点,并且右节点大于左节点,则j指向右节点
            j++;
            if(nums[j]>temp){
                nums[i]=nums[j];
                i=j;
            }else{
                break;
            }
        }
        nums[i]=temp;//将需要调整的元素放入到其该放的位置。
        
    }
    /**
     * 数据流中的中位数:中位数是有序列表中中间的数,如果是偶数个,则是中间两个的平均值。
     * 设计一个支持以下操作的数据结构:
     *  void addNum(int num):从数据流中添加一个整数到数据结构中。
     *  double findMedian():返回目前数据结构中所有元素的中位数。
     * 数据结构中所有整数都在0-100内,如何优化
     * 数据结构中99%的数在0-100内,如何优化
     * 解:使用两个优先级队列或者一个大顶堆,一个小顶堆,两个数据结构一个存储比较大的元素,
     * 一个存储比较小的元素.如果元素是奇数个,就在另外一个里面多存储一个。
     */
    class MedianInStream{
        PriorityQueue<Integer> highs=new PriorityQueue<>();
        PriorityQueue<Integer> lows=new PriorityQueue<>((nums1,nums2)->{return nums2-nums1;});
        int counts=0;
        public void addNum(int num){
            if(counts==0) {
                highs.add(num);
            }else if(counts%2==1){
                if(num<=highs.peek()){
                    lows.add(num);
                }else{
                    lows.add(highs.remove());
                    highs.add(num);
                }
            }else{
                if(num<lows.peek()){
                    highs.add(lows.remove());
                    lows.add(num);
                }else{
                    highs.add(num);
                }
            }
            counts++;
        }
        public double findMedian(){
            if(counts%2==0){
                return (0.0+highs.peek()+lows.peek())/2;
            }else{
                return highs.peek();
            }
        }
    }
    /**
     * 有序矩阵中第K小元素
     * 给定一个n*n矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
     * 解:通过二分查找,不断缩小第K小元素的值范围,改变上下界的依据是矩阵分成
     * 两部分后,小于等于mid值得元素数量是否大于等于k。如果大于等于K,则应该降
     * 低上界,否则提高下界。
     */
    public static int getKthSmallest(int[][] matrix, int k){
        int rows=matrix.length;
        int cols=matrix[0].length;
        int low=matrix[0][0];
        int high=matrix[rows-1][cols-1];
        
        int row=rows-1;
        int col=0;
        while(low<high){
            int counts=0;
            int mid=low+(high-low)/2;
            while(row>=0&&col<cols){
                if(matrix[row][col]<=mid) {
                    col++;
                    counts+=(row+1);
                }
                else row--;
            }
            if(counts>=k) high=mid;
            else low=mid+1;
            col=0;
            row=rows-1;
        }
        return low;
    }
    /**
     * 前K个高频元素:给定一个非空数组,返回频率前k高得元素。
     * 数组中前k个高频元素的集合是唯一得。
     * 解:首先使用哈希表记录每个元素出现得次数,然后建立一个小顶堆,
     * 每次插入时与堆顶元素作比较,如果堆元素小于k个,就直接插入,
     * 如果堆元素等于k个并且元素小于堆顶元素,抛弃,如果堆元素数等
     * 于k并且元素大于等于堆顶元素就弹出堆顶元素,插入当前元素。
     * 如果题目的本意不是考察堆,可以直接使用优先队列来代替堆操作。
     */
    public static int[] theKthMost(int[] nums,int k){
        HashMap<Integer,Integer> map=new HashMap<>();
        for(int num:nums){
            if(map.containsKey(num)) map.put(num, map.get(num)+1);
            else map.put(num,1);
        }
        PriorityQueue<int[]> priorityQueue=new PriorityQueue<>((a,b)->{
            return a[1]-b[1];
        });

        Iterator<Integer> iterator=map.keySet().iterator();
        while(iterator.hasNext()){
            int num=iterator.next();
            int[] ele=new int[]{num,map.get(num)};
            if(priorityQueue.size()<k){
                priorityQueue.offer(ele);
            }else{
                if(map.get(num)<priorityQueue.peek()[1]){
                    priorityQueue.poll();
                    priorityQueue.offer(ele);
                }
            }
        }
        int[] resp=new int[k];
        int i=0;
        for(int[] ele:priorityQueue){
            resp[i++]=ele[0];
            System.out.print(ele[1]+" ");
        }
        System.out.println();
        return resp;

    }
    /**
     * 逆波兰表达式求值:根据逆波兰表示法求表达式值。有效运算符包括+、
     * -、 *、/,除法只留整数部分。
     */
    public static int calExpressByRPN(String[] express){
        Stack<Integer> stack=new Stack<>();
        for(String s:express){
            if(s.equals("+")){
                int v2=stack.pop();
                int v1=stack.pop();
                stack.add(v1+v2);
            }else if(s.equals("-")){
                int v2=stack.pop();
                int v1=stack.pop();
                stack.add(v1-v2);
            }else if(s.equals("*")){
                int v2=stack.pop();
                int v1=stack.pop();
                stack.add(v1*v2);
            }else if(s.equals("/")){
                int v2=stack.pop();
                int v1=stack.pop();
                stack.add(v1/v2);
            }else{
                stack.add(Integer.parseInt(s));
            }
        }
        return stack.pop();
    }
    /**
     * 基本计算器:实现一个基本的计算器来计算一个简单的字符串表达式的值,
     * 字符串中表达式仅包含非负整数,+、-、*、/四种运算符和空格,除法只保留整数部分。
     * 解:先将乘除法的值计算出来,然后只留下加法,减法,为了简便,可以将减法后的值以
     * 反数存储,最后只算加法
     */
    public static int aCalculator(String express){
        String[] vals=express.split("[+-/*/]");
        ArrayList<Character> operators=new ArrayList<>();
        for(int i=0;i<express.length();i++){
            char c=express.charAt(i);
            if(c=='+'||c=='-'||c=='*'||c=='/') operators.add(c);
        }
        Stack<Integer> stack=new Stack<>();
        stack.push(Integer.parseInt(vals[0]));
        for(int i=0;i<operators.size();i++){
            if(operators.get(i)=='*'){
               int v1=stack.pop();
               int v2=Integer.parseInt(vals[i+1]);
               stack.push(v1*v2);
            }else if(operators.get(i)=='/'){
                int v1=stack.pop();
                int v2=Integer.parseInt(vals[i+1]);
                stack.push(v1/v2);
            }else if(operators.get(i)=='+'){
               stack.push(Integer.parseInt(vals[i+1]));
            }else if(operators.get(i)=='-'){
                stack.push(Integer.parseInt(vals[i+1])*-1);
            }
        }
        int resp=0;
        while(!stack.isEmpty()){
            resp+=stack.pop();
        }
        return resp;

    }
    /** 
     * 给你一个嵌套的整数列表 nestedList 。每个元素要么是一个整数,要么是一个列表;
     * 该列表的元素也可能是整数或者是其他列表。请你实现一个迭代器将其扁平化,使之能
     * 够遍历这个列表中的所有整数。例如 输入:[[1,1],2,[1,1]],输出:[1,1,2,1,1]
     * 实现扁平迭代器类 NestedIterator :
     * NestedIterator(List<NestedInteger> nestedList) 用嵌套列表 nestedList 初始化迭代器。
     * int next() 返回嵌套列表的下一个整数。
     * boolean hasNext() 如果仍然存在待迭代的整数,返回 true ;否则,返回 false 。
     * 解:既可以先使用递归将列表里的所有整数取出来放进一个列表里,然后直接使用。或者使用栈。
     * 每次判断有没有元素,直接判断栈顶是否是整数,如果不是就取出来,然后将里面元素重新压栈,
     * 并递归。
    */
    interface NestedInteger {
        public boolean isInteger();
        public Integer getInteger();
        public ArrayList<NestedInteger> getList();
    }
    class NestedIterator implements Iterator<Integer> {
        Stack<NestedInteger> stack=new Stack<>();
        public NestedIterator(ArrayList<NestedInteger> nestedList) {
            for(int i=nestedList.size()-1;i>=0;i--){
                stack.push(nestedList.get(i));
            }
        }
        @Override
        public Integer next() {
            return stack.pop().getInteger();
        }
        @Override
        public boolean hasNext() {
            if(stack.isEmpty()) return false;
            NestedInteger nestedInteger=stack.peek();
            if(nestedInteger==null) {
                stack.pop();
                return hasNext();
            }
            if(nestedInteger.isInteger()) return true;
            else{
                nestedInteger=stack.pop();
                ArrayList<NestedInteger> list=nestedInteger.getList();
                for(int i=list.size()-1;i>=0;i--){
                    stack.push(list.get(i));
                }
                return hasNext(); 
            }
        }
    }
    /**
     * Excel表序列号:给定一个Excel表格的列名称,返回其相应的列序号。
     * 例如:A->1,B->2,...Z->26,AA->27...
     */
    public static int getColNum(String colName){
        int resp=0;
        for(int i=0;i<colName.length();i++){
            resp+=(colName.charAt(i)-'A'+1)*Math.pow(26, colName.length()-i-1);

        }
        return resp;
    }
    /**
     * 四数相加:各给定四个包含整数的数组列表A,B,C,D,计算有多少
     * 个元组(i,j,k,l),使得A[i]+B[j]+C[k]+D[l]==0;为了简化问题,
     * 所有的A,B,C,D具有相同的长度N,且0<=N<=500,所有的整数范围
     * 在整数相加不会查超过x^31-1。
     * 解:使用哈希表存储两组的元组和和个数,然后另外两组元组和匹
     * 配哈希表。
     */
     public static int sumFourNums(int[]A,int[]B,int[]C,int[]D){
        int resp=0;
        int len=A.length;
        HashMap<Integer,Integer> map=new HashMap<>();
        int sumCD=0;
        for(int i=0;i<len;i++)
        {
            for(int j=0;j<len;j++){
                sumCD=C[i]+D[j];
                map.put(sumCD, map.getOrDefault(sumCD, 0)+1);
            }

        }
        int sumAB=0;
        for(int i=0;i<len;i++){
            for(int j=0;j<len;j++){
            sumAB=-(A[i]+B[j]);
            resp+=map.getOrDefault(sumAB, 0);
            }
        }
        return resp;
    }
    /**
     * 常数时间插入,删除和获取随机元素:设计一个支持平均时间复杂度为O(1)的,
     * 可以执行以下操作的数据结构:
     *  1.insert(val),当val不存在时,向集合中插入
     *  2.remove(val),当元素val存在时,从集合中移除
     *  3.getRandom(),随机返回一个集合中的元素,每个元素应该以相同概率被返回。
     *  解:使用两个哈希表,或者一个哈希表,一个列表,哈希表存储元素和其在列表里的索引,
     *  列表存储元素。对于插入,直接插入哈希表和列表末尾。对于移除,需要从哈希表移除,并且在
     * 列表里也移除,在列表里直接移除,会出现不必要的移动,而且空洞会在后面随机获取时,不能,
     * 一次性取得索引所以需要将移除的元素所在列表的位置上替换为列表末尾元素值,并且在哈希表里
     * 修改末尾元素移动后的索引位置,最后将列表末尾元素移除。随机获取时,直接使用随机函数获取
     * 一个索引即可。
     */
    class RandomizedSet{
        HashMap<Integer,Integer>valPosMap=new HashMap<>();
        HashMap<Integer,Integer> posValMap=new HashMap<>();
        public void insert(int val){
            int size=posValMap.size();
            if(!valPosMap.containsKey(val)){
                valPosMap.put(val, size);
                posValMap.put(size, val);
            }
        }
        public void remove(int val){
            if(valPosMap.containsKey(val)){
                int pos=valPosMap.get(val);
                int size=posValMap.size();
                valPosMap.remove(val);
                val=posValMap.get(size-1);
                posValMap.put(pos, val);
                valPosMap.put(val, pos);
                posValMap.remove(size-1);
            }

        }
        public int getRandom(){
            Random random=new Random();
            int pos=random.nextInt(posValMap.size());
            return posValMap.get(pos);
        }
        public void show(){
            for(Integer val:valPosMap.keySet()){
                System.out.print(val+":"+valPosMap.get(val));
            }
            System.out.println();
            for(Integer pos:posValMap.keySet()){
                System.out.print(pos+":"+posValMap.get(pos));
            }
            System.out.println();
        }
    }
    /**
     * 滑动窗口最大值:给定一个数组nums,有一个大小为K的滑动窗口从数组的最
     * 左侧移动到数组的最右侧,你只可以看到滑动窗口内的k个数字,滑动窗口每
     * 次向右移动一位,返回滑动窗口内的最大值。要求线性时间内解决.
     * 解1:使用一个双端队列,每次从队列中移除比当前元素小的元素,然后将当前
     * 元素添加到队列末尾,并添加队列首元素到返回数组中。由于每个元素会被清
     * 理一次,添加一次,所以平均时间复杂度为O(N)。
     * 解2:使用动态规划,将数组每k个元素分成一组,然后分别从左到右和从右到左
     * 按照每一组中累计最大存储到数组中,最后获取二者较大的。
     */
    public static int[] maxSlidingWindowDeque(int[] nums,int k){
        int len=nums.length;
        int[] resp=new int[len-k+1];
        Deque<Integer> deque=new LinkedList<>();
        deque.addFirst(nums[0]);
        for(int i=1;i<k;i++){
            while(!deque.isEmpty()&&deque.getLast()<nums[i]){
                deque.removeLast();
            }
            deque.addLast(nums[i]);
        }
        resp[0]=deque.getFirst();
        int index=1;
        for(int i=k;i<len;i++){
            while(!deque.isEmpty()&&deque.getLast()<nums[i]){
                deque.removeLast();
            }
            deque.addLast(nums[i]); 
            resp[index++]=deque.getFirst();
        }
        return resp;
    }
    public static int[] maxSlidingWindowDP(int[] nums,int k){
        int len=nums.length;
        int[] left=new int[len];
        int[] right=new int[len];
        int[] resp=new int[len-k+1];
            left[0]=nums[0];
            right[len-1]=nums[len-1];
            for(int i=1;i<len;i++){
                if(i%k==0)left[i]=nums[i];
                else left[i]=Math.max(left[i-1], nums[i]);
                int j=len-1-i;
                if((j+1)%k==0) right[j]=nums[j];
                else right[j]=Math.max(nums[j], right[j+1]);
        }
       
        for(int i=k-1;i<len;i++){
            resp[i-k+1]=Math.max(left[i],right[i-k+1]);
        }
        return resp;
    }
    /**
     * 二叉搜索树中第K小的元素:给定一个二叉搜索数,编写一个函数kthSmallest
     * 来查找其中第K个最小元素,k总是有效,并且二叉搜索树经常被修改,并且需要
     * 频繁查找第K小元素的值。\
     * 解:中序递归或者中序迭代。
     */
    public static int kthSmallest(KthSmallestNode root,int k){
        Stack<KthSmallestNode> stack=new Stack<>();
        while(true){
            while(root!=null){
                stack.add(root);
                root=root.left;
            }
            root=stack.pop();
            if(--k==0)return root.value;
            root=root.right;
        }
    }
    class KthSmallestNode{
        int value;
        KthSmallestNode left;
        KthSmallestNode right;
        public KthSmallestNode(int value){
            this.value=value;
        }
    }
    /**
     * 二叉树的最近公共祖先:给定一个二叉树,找到树中两个指定节点的最近公共祖先
     * 使用Hash表存储每个节点的父节点,然后从node1开始往上遍历,遍历的节点都标记
     * 为以访问过。然后从node2开始向上遍历,如果遇到一个节点被访问,那么该节点就
     * 是结果。
     */
    public static LowestCommonAncestorNode lowestCommonAncestor( LowestCommonAncestorNode root, LowestCommonAncestorNode node1,LowestCommonAncestorNode node2){ 
        LowestCommonAncestorNode resp=null;
        if(node1==node2)return node1;   
        HashMap<LowestCommonAncestorNode,LowestCommonAncestorNode> hashMap=new HashMap<>();
        HashSet<LowestCommonAncestorNode> set=new HashSet<>();
        hashMap.put(root, null);
        storeNode(root, hashMap);
        set.add(node1);
        while(hashMap.containsKey(node1)){
            node1=hashMap.get(node1);
            if(node1!=null)set.add(node1);
        }
        while(hashMap.containsKey(node2)){
            node2=hashMap.get(node2);
            if(set.contains(node2)) return resp=node2;
        }
        return resp;

    }
    public static void storeNode(LowestCommonAncestorNode root,HashMap<LowestCommonAncestorNode,LowestCommonAncestorNode> hashMap) {
        if(root==null) return;
        if(root.left!=null){
            hashMap.put(root.left,root);
            storeNode(root.left, hashMap);
        }if(root.right!=null){
            hashMap.put(root.right,root);
            storeNode(root.right, hashMap);
        }

    }
    class LowestCommonAncestorNode{
        int value;
        LowestCommonAncestorNode left;
        LowestCommonAncestorNode right;
        public LowestCommonAncestorNode(int value){
            this.value=value;
        }

    }
    /**
     * 二叉树的序列化与反序列化
     * 解:对于序列化,通过递归,首先将每个元素按照:存储的序号-值-父节点存储的序号-左右节点标识,来构建一个字符串
     * 并将该字符串追加到总的字符串。
     * 对于反序列化,分割字符串,取出每个元素的四个标识,然后初始化一个数组,该数组按照原来每个节点的存储序号,实例
     * 化每个节点,添加到数组中,并且依据该节点的父节点的序号,直接从数组中取出父节点,依据其是父节点的左右节点标识,
     * 将节点引用赋值给其父节点的左或者右孩子。
     * 
     */
    class SerializeBT{
        int index;
        public String serialize(SerializeBTNode root){
            this.index=0;
            StringBuilder sb=new StringBuilder();
            sb.append("0-"+root.value+"-None-None-");
            preVisit(root, sb, 0);
            return sb.toString();
           
        }
        public void preVisit(SerializeBTNode root,StringBuilder sb,int parentIndex){
            if(root==null)return;
            index++;
            if(root.left!=null){
                sb.append(index+"-"+root.left.value+"-"+parentIndex+"-0-");
                preVisit(root.left, sb, index);
            }
            if(root.right!=null){
                sb.append(index+"-"+root.right.value+"-"+parentIndex+"-1-");
                preVisit(root.right, sb, index);
            }

        }
        public SerializeBTNode deserialize(String sb){
            String[] ss=sb.split("-");
            SerializeBTNode[] serializeBTNodes=new SerializeBTNode[ss.length];
            SerializeBTNode root=new SerializeBTNode(Integer.parseInt(ss[1]));
            serializeBTNodes[0]=root;
            for(int i=4;i<serializeBTNodes.length;i+=4){
                SerializeBTNode serializeBTNode=new SerializeBTNode(Integer.parseInt(ss[i+1]));
                serializeBTNodes[i/4]=serializeBTNode;
                if(ss[i+3].equals("0")){
                    serializeBTNodes[Integer.parseInt(ss[i+2])].left=serializeBTNode;
                }else{
                    serializeBTNodes[Integer.parseInt(ss[i+2])].right=serializeBTNode;
                }
            }
            return root;

        }
        

    }
    class SerializeBTNode{
        int value;
        SerializeBTNode left;
        SerializeBTNode right;
        public SerializeBTNode(int value){
            this.value=value;
        }
    }
    /**
     * 最大数:给定一组非负数,重新排列它们的顺序使之成为一个最大整数
     */
    public static String maxInteger(int[] nums){
        String[] numsString=new String[nums.length];
        for(int i=0;i<nums.length;i++){
            numsString[i]=String.valueOf(nums[i]);
        }
        StringBuilder sb=new StringBuilder();
        Arrays.sort(numsString,(a,b)->{
            String ab=a+b;
            String ba=b+a;
            return ba.compareTo(ab);
        });
        for(String s:numsString){
            sb.append(s);
        }
        if(sb.charAt(0)=='0')return "0";
        return sb.toString();
    }
    /**
     * 摆动排序:给定一个无序数组nums,将它重新排列成nums[0]<nums[1]>nums[2]<nums[3]...的顺序。
     */
    public static void swingSort(int[] nums){
        Arrays.sort(nums);
        int len=nums.length;
        int midIndex=0;
        if(len%2==1)midIndex=len/2;
        else midIndex=len/2-1;
        int[] temp=new int[len];
        int index=0;
        int leftIndex=midIndex;
        int rightIndex=len-1;
        while(rightIndex>midIndex){
            temp[index++]=nums[leftIndex--];
            temp[index++]=nums[rightIndex--];
        } 
        if(len%2==1)temp[index]=nums[0];
        for(int i=0;i<len;i++)nums[i]=temp[i];
    }
    /**
     * 寻找峰值:峰值元素指的是其值大于左右相邻值得元素。给定一个数组nums,
     * 其中nums[i]!=nums[i+1],找到峰值元素并返回其索引数组可能包含多个峰值,
     * 在这种情况下返回任何一个峰值元素所在位置即可。假设nums[-1]=nums[n]为
     * 无穷大。希望时间复杂度为O(log(N))
     * 解:二分法寻找最大值,任意一个元素可能在升序坡上或者降序坡上,还可能就在峰值上。
     */
    public static int findPeakElement(int[] nums){
        int len=nums.length;
        int low=0;
        int high=len-1;
        int mid=0;
        while(low<high){
            mid=low+(high-low)/2;//清楚几点:当超过2个元素时,mid后面肯定至少有一个元素。
            if(nums[mid]>nums[mid+1]) high=mid;//由于寻找得比较大的值,所以nums[mid]>nums[mid+1]时,比较大得值肯定在包括mid的左边,否则在mid的右边。
            else low=mid+1;
        }
        return low;

    }
    /**
     * 寻找重复数:给定一个包含n+1个元素的数组nums,其数字都在1到n之间,包括1和n,
     * 可知至少存在一个重复数,假设只有一个重复整数,找出这个数,
     * 说明:不能更改原数组,空间复杂度O(1),时间复杂度小于O(N^2),只有一个重复数
     * 字,出现的次数不止一次。
     * 解1:对于数组nums={1,3,4,2,2},我们发现小于等于数组元素的个数分别是:
     * num[i]:1   2   3   4
     * counts:1   3   4   5
     * 所以目标元素肯定在于小于等于数组元素的个数大于本元素值左边,在小于等于本元素的右边
     * 解2:使用快慢指针:将i->nums[i]看成路径,所以快慢指针从0开始,快指针每次移动2步,
     * 慢指针每次移动一步,快慢指针相遇后,快指针从相遇点开始,慢指针从0开始,再次相遇就是
     * 答案。
     */
    public static int findRepeatableNum(int[] nums){
        int len=nums.length;
        int low=1;
        int high=len-1;
        int mid=0;
        while(low<=high){
            int counts=0;
            mid=low+(high-low)/2;
            for(int num:nums){
                if(num<=mid)counts++;
            }
            
            if(counts<=mid)low=mid+1;
            else {
                high=mid-1;
            }
        }
        return mid;
    }
    public static int findRepeatableNum2(int[] nums){
        int slow=0;
        int fast=0;
        do{
            slow=nums[slow];
            fast=nums[fast];
            fast=nums[fast];
        }while(fast!=slow);
        slow=0;
        while(slow!=fast){
            slow=nums[slow];
            fast=nums[fast];
        }
        return fast;
    }
    /**
     * 计算右侧小于当前元素的个数:给定一个整数数组nums,按照要求返回一个新数组counts,该数
     * 组的性质:counts[i]的值是nums[i]右侧小于nums[i]的元素个数。
     * 说明:0<=nums.length<10^5
     * -10^4<=nums<=10^4
     * 未做,哭了
     */
    public static int[] countsSmaller(int[] nums){
        int len=nums.length;
        int[] counts=new int[len];

        return counts;

    }
    /**
     * 至少有k个重复字符的字符串:找出给定字符串中最长字串T,T中的每个字符出现的次数不
     * 少于K,输出T的长度,例如S="aaabb",K=3,输出:3
     * 解:使用分治思想,即每次统计所有字符出现的次数,然后将出现未达到次数的字符之间
     * 的字串再次递归调用。
     */
    static int  longestSubstringResp=0;
    public static int longestSubstring(String s,int k){
        longestSubstringDigui(s, k);
        return longestSubstringResp;
    }
    public static void longestSubstringDigui(String s,int k){
        if(s.length()<k) return;
        int[] counts=new int[26];
        Arrays.fill(counts,0);
        for(int i=0;i<s.length();i++){
            counts[s.charAt(i)-'a']++;
        }
        ArrayList<Integer> split=new ArrayList<>();
        split.add(-1);
        for(int i=0;i<s.length();i++){
            if(counts[s.charAt(i)-'a']<k){
                split.add(i);
            }
        }
        if(split.size()==1){
            longestSubstringResp=Math.max(longestSubstringResp,s.length());
        }else{
            split.add(s.length());
            for(int i=0;i<split.size()-1;i++){
                String subString=s.substring(split.get(i)+1, split.get(i+1));
                if(split.get(i+1)-split.get(i)+1>longestSubstringResp){
                    longestSubstringDigui(subString, k);
                }
            }
        }
    }
    /**
     * 二叉树中的最大路径和:给定一个非空二叉树,返回其最大路径和
     * 说明:路径指的是从一个结点开始,到达任意多个后代节点之间的
     * 所有路径。例如node1->node2,node1->node3,那么这两个都是node1
     * 后面的路径。
     * 解:使用动态规划的思想,
     */
    static int largestPathSumResp=Integer.MIN_VALUE;
    public static int maxPathSum(LargestPathSumNode root) {
        if(root.left==null&&root.right==null)return root.val;
        largestPathSumDigui(root);
        return largestPathSumResp;

    }
    public static int largestPathSumDigui(LargestPathSumNode root){
        if(root==null) return 0;
        int leftSum=Math.max(0,largestPathSumDigui(root.left));
        int rightSum=Math.max(0,largestPathSumDigui(root.right));
        largestPathSumResp=Math.max(largestPathSumResp,leftSum+rightSum+root.val);
        return Math.max(leftSum,rightSum)+root.val;
    }
    class LargestPathSumNode{
        int val;
        LargestPathSumNode left;
        LargestPathSumNode right;
        public LargestPathSumNode(int val){
            this.val=val;
        }
    }
        /**
     * 最长连续序列:给定一个未排序的整数数组,找到最长的连续序列的长度。
     * 要求:算法的时间复杂度未O(N)。例如:nums={100,4,200,1,2,3},则最长
     * 连续序列为[1,2,3,4],长度为4。
     */
    public static int longestSequence(int[] nums){
        Stack<Integer> stack=new Stack<>();
        int resp=0;
        for(int num:nums) stack.push(num);
        for(int num:stack){
            if(!stack.contains(num-1)){//只有没有比他更小的连续数才能进入内循环
                int counts=1;
                int start=num+1;
                while(stack.contains(start)) {
                    counts++;
                    start++;
                }
                resp=Math.max(resp, counts);
            }
        }
        return resp;

    }
    /**
     * 打家劫舍:你是一个专业小偷,计划偷袭沿街房屋,每个房屋内有一定的现金
     * 影响你偷袭的唯一因素是相邻的房屋装有相互连通的防盗系统,如果相邻的房屋内
     * 同一晚上被小偷偷袭就会报警。给你一个数组,每个元素是没见房屋存有的现金,不
     * 允许报警的情况下,盗取最高金额。
     */
    public static int getMaxMoney(int[] nums){
        int len=nums.length;
        int no=0;
        int yes=0;
        for(int i=0;i<len;i++){
            int noTemp=Math.max(yes,no);
            int yesTemp=no+nums[i];
            no=noTemp;
            yes=yesTemp;
        }
        return Math.max(yes,no);
    }
    /**
     * 完全平方数:给定正整数n,找到若干个完全平方数,比如1,4,9,16...
     * 使得它们的和等于n,要求组成和的完全平方数的个数最少。
     */
    public static int sequareNum(int n){
        int temp=(int)Math.sqrt(n);
        int[] dp=new int[n+1];
        Arrays.fill(dp, Integer.MAX_VALUE-10);
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<temp+1;j++){
                if((j^2)>i) break;
                dp[i]=Math.min(dp[i], dp[i-(j^2)]+1);
            }
           
        }
        return dp[n];
    }
    /**
     * 最长上升子序列:给定一个无序的整数数组,找到其中最长上升子序列的长度,
     * 算法时间复杂度为O(Nlog(N)).
     * 解:dp[i]表示第i个数结尾的最长上升子序列。
     */
    public static int longestUpSequence(int[] nums){
        int len=nums.length;
        int[] dp=new int[len];
        dp[0]=1;
        for(int i=1;i<len;i++){
            int max=0;
            for(int j=0;j<i;j++){
                if(nums[j]<nums[i]){
                    max=Math.max(max, dp[j]);
                }
            }
            dp[i]=max+1;
            System.out.println(dp[i]);
        }
        return dp[len-1];

    }
    /**
     * 零钱兑换:给定不同面额的硬币coins和一个总金额编写函数计算可以凑成总金额的
     * 最少硬币数,如果没有任何一种可以凑成总金额的方案,则返回-1.
     */
    public static int coinExchange(int[] coins,int amount){
        int[] dp=new int[amount+1];
        Arrays.fill(dp,amount+1);
        dp[0]=0;
        for(int i=1;i<=amount;i++){
            for(int j=0;j<coins.length;j++){
                if(i>=coins[j]){
                   dp[i]=Math.min(dp[i], dp[i-coins[j]]+1); 
                }
            }
            System.out.println(i+":"+dp[i]);
        }
        return dp[amount]==amount+1?-1:dp[amount];
    }
    /**
     * 矩阵种最长的递增路径
     * 给定一个整数举证,找出最长递增路径的长度:移动的方向只能是上下左右
     * 例如:9,9,9
     *       6,6,8
     *       2,1,1
     * 则最长路径是1,2,6,9.
     * 解:使用记忆优先深度搜索
     */
    public static int longestPath(int[][] nums){
        int rows=nums.length;
        int cols=nums[0].length;
        boolean[][] isVisited=new boolean[rows][cols];
        int[][] dp=new int[rows][cols];
        int resp=0;
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                resp=Math.max(resp,longestPathDigui(nums, isVisited, dp, i, j));
                System.out.print(dp[i][j]+" ");
            }
            System.out.println();
        }
        return resp+1;
    }
    public static int longestPathDigui(int[][] nums,boolean[][] isVisited,int[][] dp,int row,int col){
        int rows=nums.length;
        int cols=nums[0].length;
        if(row-1>=0&&nums[row][col]>nums[row-1][col]){
            if(isVisited[row-1][col]) dp[row][col]=Math.max(dp[row-1][col]+1, dp[row][col]);
            else dp[row][col]=Math.max(longestPathDigui(nums, isVisited, dp, row-1, col)+1, dp[row][col]);
        }
        if(row<rows-1&&nums[row][col]>nums[row+1][col]){
            if(isVisited[row+1][col]) dp[row][col]=Math.max(dp[row+1][col]+1, dp[row][col]);
            else dp[row][col]=Math.max(longestPathDigui(nums, isVisited, dp, row+1, col)+1, dp[row][col]);
        }
        if(col-1>=0&&nums[row][col]>nums[row][col-1]){
            if(isVisited[row][col-1]) dp[row][col]=Math.max(dp[row][col-1]+1, dp[row][col]);
            else dp[row][col]=Math.max(longestPathDigui(nums, isVisited, dp, row, col-1)+1, dp[row][col]);
        }
        if(col<cols-1&&nums[row][col]>nums[row][col+1]){
            if(isVisited[row][col+1]) dp[row][col]=Math.max(dp[row][col+1]+1, dp[row][col]);
            else dp[row][col]=Math.max(longestPathDigui(nums, isVisited, dp, row, col+1)+1, dp[row][col]);
        }
        isVisited[row][col]=true;
        return dp[row][col];

    }
    /**
    * 反转二进制颠倒给定的32位无符号整数二进制。例如-3的表示是11111111111111111111111111111101,
    输出则是10111111111111111111111111111111
    */
    public static int reverseNum(int num){
        int[] reversedNum=new int[32];
        for(int i=0;i<32;i++){
            reversedNum[i]=num&1;
            num>>>=1;
            System.out.print(reversedNum[i]);
        }
        System.out.println();
        int resp=0;
        if(reversedNum[0]==1){
            for(int i=31;i>0;i--){
                if(reversedNum[i]==0)reversedNum[i]=1;
                else reversedNum[i]=0;
                System.out.print(reversedNum[i]);
            }
            System.out.println(1);
            int c=1;
            for(int i=31;i>0;i--){
                int temp=reversedNum[i]&c;
                reversedNum[i]=reversedNum[i]|c;
                c=temp;
                System.out.print(reversedNum[i]);
            }
            System.out.println(1);
        }
        int n=1;
        for(int i=31;i>0;i--){
            resp+=(reversedNum[i]*n);
           
            n*=2;
        }
        
        return reversedNum[0]==1?-resp:resp;
    }
    /** 
    * 验证回文串:
   */
    /**
     * 分割回文串:给定一个字符串s,将s分割成一些字串,使每个
     * 字串都回文串,返回s的所有的分割方案
     * 解:采用递归的思想,每次截取字串的一部分,如果是回文,
     * 就加入前部分,递归剩下的一部分,如果字串为空,就把list加入最终的list里。
     */
    public static  List<List<String>> splitToHuiwenString(String s){
        List<List<String>> resp=new ArrayList<>();
        String[] strs=new String[0];
        splitToHuiwenStringDigui(s, 0, s.length(), resp, strs);
        return resp;

    }
    public static void splitToHuiwenStringDigui(String s,int left,int right,List<List<String>> resp,String[] ele){
        if(left==right){
            List<String> list=Arrays.asList(ele);
            resp.add(list);
            return;
        }
        for(int i=left;i<right;i++){
            if(isHuiwen(s, left, i)){
                String[] strts=new String[ele.length+1];
                System.arraycopy(ele, 0,strts, 0, ele.length);
                strts[ele.length]=s.substring(left,i+1);
                splitToHuiwenStringDigui(s, i+1, right, resp, strts);
            }
        }
    }
    public static boolean isHuiwen(String s,int start,int end){
        while(start<=end){
            if(s.charAt(start)!=s.charAt(end)){
                return false;
            }else{
                start++;
                end--;
            }
        }
        return true;
    }
    /**
     * 单词拆分:给定一个非空字符串s和一个包含非空单词的列表wordDict,判
     * 断s是否可以分解为一个或者多个在字典里出现的单词。
     * 解:定义dp[i]位字符串s的前i个字符组成的子字符串是否可以满足题意。
     */
    public static boolean canBeSplited(String s,List<String> wordDict){
        HashSet<String> set=new HashSet<>(wordDict);
        boolean[] dp=new boolean[s.length()+1];
        dp[0]=true;
        for(int i=0;i<s.length();i++){
            for(int j=i;j>=0;j--){
                if(dp[j]&&set.contains(s.substring(j,i+1))){
                    dp[i+1]=true;
                    break;
                }
            }
            
        }
        return dp[s.length()];
    }
    /**
     * 单词拆分II:给定一个非空字符串s和字典wordDict,在字符串种增加空格来分割
     * 字符串,使得每个单词都在词典中,返回所有可能的句子。
     */
    public static String[] wordBreak(String s,String[] wordList){
        HashSet<String> set=new HashSet<>(Arrays.asList(wordList));
        LinkedList<String>[] dp=new LinkedList[s.length()+1];
        LinkedList<String> initial=new LinkedList<>();
        initial.add("");
        dp[0]=initial;
        for(int i=1;i<=s.length();i++){
            LinkedList<String> list=new LinkedList<>();
            for(int j=0;j<i;j++){
                if(dp[j].size()>0&&set.contains(s.substring(j,i))){
                    for(String string:dp[j]){
                        list.add(string+(string.equals("")?"":" ")+s.substring(j,i));
                    }
                }
            }
            dp[i]=list;
        }
        return dp[s.length()].toArray(new String[0]);


    }
    /**
     * 前缀树:实现一个前缀树Trie,包含insert,search,startWith三个操作
     */
    class Trie{
        TrieNode root;
        public Trie(TrieNode root){
            this.root=root;
        }
        public void insert(String word){
            TrieNode node=root;
            for(int i=0;i<word.length();i++){
                if(!node.next.containsKey(word.charAt(i))){
                    node.next.put(word.charAt(i),new TrieNode());
                }
                if(i==word.length()-1){
                    node.has[word.charAt(i)-'a']=true;
                }
                node=node.next.get(word.charAt(i));
            }
        }
        public boolean search(String word){
            TrieNode node=root;
            for(int i=0;i<word.length();i++){
                if(!node.next.containsKey(word.charAt(i))){
                    return false;
                }
                if(i==word.length()-1){
                    if(!node.has[word.charAt(i)-'a']) return false;
                    else return true;
                }
                node=node.next.get(word.charAt(i));
            }
            return false;
        }
        public boolean startWith(String word){
            TrieNode node=root;
            for(int i=0;i<word.length();i++){
                if(!node.next.containsKey(word.charAt(i))){
                    return false;
                }
                node=node.next.get(word.charAt(i));
            } 
            return true;
        }
    }
    class TrieNode{
        boolean[] has=new boolean[26];
        HashMap<Character,TrieNode> next=new HashMap<>();
    }
    /**
     * 打印数组:给定一个数表示一个十进制的位数,请从1打印数字到这个十位数的最大数,例如n=3,因此打印到999.
     */
    public static void printNum(int n){//算法入口
        if(n<1) return;
        char[] maxValue=new char[n];
        Arrays.fill(maxValue, '9');
        char[] num=new char[n];
        Arrays.fill(num, '0');
        while(!isMaxValue(num,maxValue)){
            incrementNum(num);
            int i=0;
            while(num[i]=='0'){
                i++;
            }
            for(;i<n;i++){
                System.out.print(num[i]);
            }
            System.out.println();
        }
    }
    public static void incrementNum(char[] num){//加一操作
        int end=num.length-1;
        int c=1;//进位
        int s=0;//余数
        while(end>=0){
            s=num[end]-'0';
            int tempC=(s+c)/10;
            s=(s+c)%10;
            c=tempC;
            num[end]=(char)(s+'0');
            end--;
            if(c==0)break;
        }
    }
    public static boolean isMaxValue(char[] num,char[] maxValue){//判断是否到最大数
        for(int i=0;i<num.length;i++){
            if(num[i]!=maxValue[i])return false;
        }
        return true;
    }
    /**
     * 二叉树的镜像:输入一个二叉树,输出该二叉树的镜像
     */
    public static BTMirrorNode BTMirror(BTMirrorNode root){
        if(root==null)return null;
        LeetCode leetCode=new LeetCode();
        LeetCode.BTMirrorNode resp=leetCode.new BTMirrorNode(root.value);
        BTMirrorDigui(root,resp,leetCode);
        return resp;

    }
    public static void BTMirrorDigui(BTMirrorNode parent,BTMirrorNode mirror,LeetCode leetCode){
        if(parent.left!=null){
            LeetCode.BTMirrorNode right=leetCode.new BTMirrorNode(parent.left.value);
            mirror.right=right;
            BTMirrorDigui(parent.left,right,leetCode);
        }
        if(parent.right!=null){
            LeetCode.BTMirrorNode left=leetCode.new BTMirrorNode(parent.right.value);
            mirror.left=left;
            BTMirrorDigui(parent.right,left,leetCode);
        }

    }
    class BTMirrorNode{
        BTMirrorNode left;
        BTMirrorNode right;
        int value;
        public BTMirrorNode(int value){
            this.value=value;
        }
    }
    /**
     * 栈的压入与弹出序列:给出两个序列,第第一个序列是栈的压入顺序,判断第二个
     * 是否是栈的弹出顺序
     */
    public static boolean isPopSequence(int[] pushSeq,int[] popSeq){
        int pushPtr=0;
        int popPtr=0;
        Stack<Integer> stack=new Stack<>();
        while(popPtr<popSeq.length&&pushPtr<pushSeq.length){
            if(!stack.isEmpty()){
                if(pushSeq[pushPtr]!=popSeq[popPtr]&&stack.peek()!=popSeq[popPtr]){
                    stack.push(pushSeq[pushPtr++]);
                }
                else if(pushSeq[pushPtr]==popSeq[popPtr]){
                    pushPtr++;
                    popPtr++;
                }
                else if(stack.peek()==popSeq[popPtr]){
                    stack.pop();
                    popPtr++;
                }
            }
            else{
                if(pushSeq[pushPtr]!=popSeq[popPtr]){
                    stack.push(pushSeq[pushPtr++]);
                }else{
                    pushPtr++;
                    popPtr++;
                }
            }
        }
        while(!stack.isEmpty()){
            if(stack.pop()!=popSeq[popPtr++])return false;
        }
        return true;
    }
    /**
     * 按层打印二叉树
     */
    public static void printBTByLayer(PrintBTByLayerNode root){
        if(root==null)return;
        List<PrintBTByLayerNode> deque=new LinkedList<>();
        deque.add(root);
        while(!deque.isEmpty()){
            if(deque.get(0).left!=null){
                deque.add(deque.get(0).left);
            }if(deque.get(0).right!=null){
                deque.add((deque.get(0).right));
            }
            System.out.print(deque.remove(0).value);
        }
        
    }
    class PrintBTByLayerNode{
        int value;
        PrintBTByLayerNode left;
        PrintBTByLayerNode right;
        public PrintBTByLayerNode(int value){
            this.value=value;
        } 
    }
    /**
     * 判断序列是否是某二叉搜索树的后序遍历序列,假设所有的节点值都不同。
     */
    public static boolean isPostSeq(int[] seq){
        return isPostSeqDigui(seq, 0, seq.length-1);

    }
    public static boolean isPostSeqDigui(int[] seq,int left,int right){
        if(left>=right)return true;
        int leftIndex=left;
        while(leftIndex<right){
            if(seq[leftIndex]>seq[right]){
                break;
            }
            leftIndex++;
        }
        for(int i=leftIndex;i<right;i++){
            if(seq[i]<seq[right])return false;
        }
        return isPostSeqDigui(seq, left, leftIndex-1)&&isPostSeqDigui(seq, leftIndex, right-1);
    }
    static int remain;
    public static void printPath(BinaryTreeNode root,int expectedSum){
        remain=expectedSum;
        if(root==null) return;
        Stack<Integer> stack=new Stack<>();
        printPathDigui(root, stack);

    } 
    public static void printPathDigui(BinaryTreeNode parent,Stack<Integer> stack){
        stack.push(parent.value);
        remain-=parent.value;
        if(parent.left==null&&parent.right==null){
            if(remain==0){
                stack.forEach(ele->{System.out.print(ele+" ");});
                System.out.println();
            }       
        }
        if(parent.left!=null){
            printPathDigui(parent.left, stack);
        }
        if(parent.right!=null){
            printPathDigui(parent.right, stack);
        }
        remain+=parent.value;
        System.out.println(stack.pop());        
        

    }
    /**
     * 二叉搜索树与双向链表:输入一个二叉搜索树,将该二叉搜索树转换为一个排序的双向链表,要求不能创建任何新节点,智能调整树中的节点指针
     * 解1:使用一个指针记录上次访问的节点,另一个指针记录当前的指针。思想是递归
     * 解2:使用栈实现非递归方法。
     */
    static BinaryTreeNode  lastNode=null;
    public static BinaryTreeNode BT2DLinkedlist(BinaryTreeNode root){
        if(root==null)return null;
        BT2DLinkedlistDigui(root);
        BinaryTreeNode head=root;
        while(head.left!=null) head=head.left;
        return head;

    }
    public static void BT2DLinkedlistDigui(BinaryTreeNode parentNode){
        BinaryTreeNode currentNode=parentNode;
        if(currentNode.left!=null){
            BT2DLinkedlistDigui(currentNode.left);
        }
        currentNode.left=lastNode;
        if(lastNode!=null)lastNode.right=currentNode;
        lastNode=currentNode;
        if(currentNode.right!=null){
            BT2DLinkedlistDigui(currentNode.right);
        }
    }
    public static BinaryTreeNode BT2DLinkedlist2(BinaryTreeNode root){
        if(root==null)return null;
        Stack<BinaryTreeNode>stack=new Stack<>();
        BinaryTreeNode currentNode=root;
        BinaryTreeNode preNode=null;
        BinaryTreeNode headNode=null;
        stack.push(currentNode);
        currentNode=currentNode.left;
        while(!stack.isEmpty()||currentNode!=null){
            while(currentNode!=null){
                    stack.push(currentNode);
                    currentNode=currentNode.left;
            }
            currentNode=stack.pop();
            currentNode.left=preNode;
            if(preNode!=null){
                preNode.right=currentNode;
            }else{
                headNode=currentNode;
            }
            preNode=currentNode;
            currentNode=currentNode.right;
        
        }
        return headNode;
    }
    /**
     * 非递归实现中序遍历
     */
    public static void NoDiguiMidVisistBT(BinaryTreeNode root){
        if(root==null)return;
        Stack<BinaryTreeNode> stack=new Stack<>();
        stack.push(root);
        BinaryTreeNode currentNode=root.left;
        while(!stack.isEmpty()||currentNode!=null){
            while(currentNode!=null){
                stack.push(currentNode);
                currentNode=currentNode.left;
            }
            currentNode=stack.pop();
            System.out.print(currentNode.value+"->");
            currentNode=currentNode.right;
        }
        System.out.println();
    }
    /**
     * 非递归前序遍历
     */
    public static void NoDiguiPreVisitBT(BinaryTreeNode root){
        if(root==null)return;
        Stack<BinaryTreeNode> stack=new Stack<>();
        BinaryTreeNode currentNode=root;
        while(!stack.isEmpty()||currentNode!=null){
            System.out.print(currentNode.value+"->");
            if(currentNode.right!=null) stack.push(currentNode.right);
            if(currentNode.left==null){
                if(!stack.isEmpty()) currentNode=stack.pop();
                else currentNode=null;
            }else{
                currentNode=currentNode.left;
            }
        }
        System.out.println();
    }
    /**
     * 非递归后续遍历
     * 解:主要思路是使用一个指针来记录上次访问的节点。
     */
    public static void NoDiguiPostVisitBT(BinaryTreeNode root){
        if(root==null) return;
        Stack<BinaryTreeNode> stack=new Stack<>();
        BinaryTreeNode currentNode=root;
        BinaryTreeNode preNode=null;
        while(!stack.isEmpty()||currentNode!=null){
            while(currentNode!=null){//根节点和左节点入栈
                stack.push(currentNode);
                currentNode=currentNode.left;
            }
            if(!stack.isEmpty()){
                currentNode=stack.pop();//弹出一个节点
                if(currentNode.right==null||preNode==currentNode.right){//如果该节点的右子节点为空或者上一次访问的是当前节点的右子节点则访问当前节点
                    System.out.print(currentNode.value+"->");//访问当前节点
                    preNode=currentNode;//记录上一次访问的节点
                    currentNode=null;//此操作是为了下次迭代时跳过入栈操作,而是进入出栈操作。
                }else{//条件不满足就不访问。
                    stack.push(currentNode);//将当前节点入栈
                    currentNode=currentNode.right;//重置当前节点
                }
            }
        }
    }
    /**
     * 字符串排列:输入一个字符串,打印出由该字符串中字符组成的所有排列,例如:
     * abc的排列右abc,acb,bac,bca,cab,cba.
     * 解释:广度优先遍历+回溯
     */
    public static void permutation(String str){
        boolean[] isVisited=new boolean[str.length()];
        List<String> strs=new ArrayList<>();
        permutationDigui(str, isVisited, strs, new StringBuilder(str.length()));
        for(String s:strs)System.out.println(s);

    }
    public static void permutationDigui(String str,boolean[] isVisited,List<String> strs,StringBuilder s){
        
        if(s.length()==str.length()) {
            strs.add(s.toString());
            return;
        }
        for(int i=0;i<isVisited.length;i++){
            if(!isVisited[i]){
                isVisited[i]=true;
                permutationDigui(str, isVisited, strs, s.append(str.charAt(i)));
                s.deleteCharAt(s.length()-1);
                isVisited[i]=false;
            }
        }

    }
    /**
     * 输入一个含有8个数字的数组,判断有没有可能把8个数字放到正方体的8个顶
     * 点上,使得正方体上三组相对的面上的4个顶点的和相等。
     * 解:先使用上述方法求出8个数字的所有排列,然后一一验证。
     */
    /**
     * 两条链表的第一个公共节点:
     * 解:先遍历两个链表,计算二者长度L1,L2,然后求出二者长度的差L,让长的先走L步,然后二者再
     * 同时遍历,如果相等,那么就是第一个公共节点
     */ 
    /**
     * 寻找二叉树里两节点路径的的最低公共节点。
     */
    static boolean isStop=false;
    public static BinaryTreeNode postVisitBT(BinaryTreeNode root,BinaryTreeNode node1,BinaryTreeNode node2){
        BinaryTreeNode resp=null;
        List<BinaryTreeNode> list1=new LinkedList<>();
        List<BinaryTreeNode> list2=new LinkedList<>();
        postVisitBTDigui(root,list1, node1);
        isStop=false;
        postVisitBTDigui(root,list2, node2);
        for(BinaryTreeNode binaryTreeNode:list1)System.out.print(binaryTreeNode.value+"->");
        System.out.println();
        for(BinaryTreeNode binaryTreeNode:list2)System.out.print(binaryTreeNode.value+"->");
        System.out.println();
        for(int i=0;i<list1.size()&&i<list2.size();i++){
            if(list1.get(i)!=list2.get(i)){
                resp=list1.get(i-1);
                break;
            }
        }
        return resp;



    }
    public static void postVisitBTDigui(BinaryTreeNode root,List<BinaryTreeNode> list,BinaryTreeNode node){
        if(isStop)return;
        if(node==root){
            list.add(node);
            isStop=true;
            return;
        }
        list.add(root);
        if(root.left!=null){
           postVisitBTDigui(root.left, list,node); 
        } 
        if(root.right!=null){
            postVisitBTDigui(root.right,list, node);
        }if(!isStop){
            list.remove(list.size()-1);
        }
        
    }
    /**
     * 寻找有序数组中某个数的第一次出现的位置
     */
    public static int firstPlace(int[] nums,int num){
        int low=0;
        int high=nums.length-1;
        
        while(low<=high){
            int mid=low+(high-low)/2;
            if(nums[mid]==num){
                if((mid>0&&nums[mid-1]!=num)||mid==0){
                    return mid;
                }else{
                    high=mid-1;
                }
            }
            else if(nums[mid]>num){
                high=mid-1;
            }else{
                low=mid+1;
            }
        }
        return -1;
    }
    /**
     * 寻找有序数组中某个数的最后一次出现的位置 
     * 
     * */ 
    public static int lastPlace(int[] nums,int num){
        int low=0;
        int high=nums.length-1;
        
        while(low<=high){
            int mid=low+(high-low)/2;
            if(nums[mid]==num){
                if((mid<nums.length-1&&nums[mid+1]!=num)||mid==nums.length-1){
                    return mid;
                }else{
                    low=mid+1;
                }
            }
            else if(nums[mid]>num){
                high=mid-1;
            }else{
                low=mid+1;
            }
        }
        return -1;
    }
    /**
     * 统计有序数组中某个数字出现的次数。
     * 解:上述两个算法的结合。
     */
    /**
     * 找出数组中只出现一次的两个数字,其他数字都出现两次
     * 解:首先全部异或,然后将结果的的二进制里出现1的一个位置记下来,
     * 然后再遍历,将该位置是1的数分为一组,是0的分为一组。同时两组分别异或。
     */
    /**
     * 数组中求和为s的两个数
     * 解:定义前后两个指针,如果这个之和大于s,则后面指针往前走,如果小于s则前面指针往后走。
     * 相等就返回两指针指向的数
     */
    /**
     * 旋转句子中单词的顺序,例如:i am a student.,旋转之后为:student. a am i。
     * 解:先反转所有字符,然后按单词反转单词里的字符顺寻
     */
    public static void main(String[] args){
    }
	class BinaryTreeNode{
    int value;
    BinaryTreeNode left;
    BinaryTreeNode right;
    public BinaryTreeNode(int value){
        this.value=value;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网络自动化工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值