Summary of Swordfinger offer Title

Character string

The first character in a string stream that occurs only once

Title Description:

Implement a function to find the first character in a character stream that occurs only once. For example, when you read only the first two characters "go" from the character stream, the first character that occurs only once is "g". When you read the first six characters "google" from the character stream, the first character that occurs only once is "l".

Solving Ideas 1:

(1) Use a HashMap < Character, Integer > to store characters: number; and a global variable String to store the order of the current stream, str+=ch;
(2) Walk through the HashMap and if you find a character with a number of one in the HashMap, use the indexOf() method to find the index of the character and return the character.
(3) Note that a map is an out-of-order store, and that all characters that need to be identified and retrieved with the smallest index in all keySet s need to be traversed.

import java.util.Map;
import java.util.TreeMap;
public class Solution {
    //Insert one char from stringstream
    String str="";
    Map<Character,Integer> map=new TreeMap<Character,Integer>();
    public void Insert(char ch){
        if(map.containsKey(ch)){
            map.put(ch,map.get(ch)+1);
        }else{
            map.put(ch,1);
        }
        str+=ch;
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce(){
       int index=Integer.MAX_VALUE;
       char result='#';
       for(Character c: map.keySet()){
            if(map.get(c) == 1){
                if(str.indexOf(c) < index){//Since map s are out of order, additional characters are needed to get the smallest index
                    index = str.indexOf(c);
                    result = str.charAt(index);
                }
            }
        }
        return result;
    }
}

Solving Ideas 2

(1) Use a hash array for counting. The length of the array is 128, because ASCII is 128 characters, so this solution is only for English strings.

(2) Queues are used to cache input streams. Only new characters are queued (whether or not the elements are duplicated, and only one element value is guaranteed to exist in the queue). Hash arrays record the number of occurrences of characters. When queued, determine if the first character in the queue is duplicated (the number in the hash array is greater than 1). If it is duplicated, the queue is directly queued, otherwise, this character is returned.

(3) Loop through the above (1) and (2) steps until the queue is empty.

Several key API s used

Character c: c.charValue();

import java.util.*;
public class Solution {
    //Insert one char from stringstream
    int[] charCount=new int[128];
    Queue<Character> queue=new LinkedList<Character>();
    public void Insert(char ch){
        if(charCount[ch]==0){
            queue.add(ch);//There is only one duplicate element in the queue;
        }
        charCount[ch]++;//Count plus one
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce(){
       Character ch=null;
       while(( ch=queue.peek())!=null){
           char c=ch.charValue();
           if(charCount[c]==1){
               //Only one?
               return c;
           }else{
               //Out of Queue
               queue.poll();//Remove the duplicate elements, and then, depending on the characteristics of the queue, you can get the first non-duplicate value in order (the head of the queue)
           }
       }
        return '#';
    }
}

Determines whether a string is represented as a number

Title Description:

Implement a function to determine whether a string represents a numeric value, including integers and decimals.

Examples'+100','5e2','-123','3.1416','and'-1E-16'all represent values.

Counterexamples are "12e", "1a3.14", "1.2.3", "and"+5"12e+4.3"

Solving ideas:

Traverse through each character in the string, excluding counterexamples for special locations where + - E numbers appear

(1) When the current character is: +or-the first occurrence of the character must be at str[0], and the second occurrence must be after E or e;

(2) The current character is:.A decimal point cannot appear after E.

(3) When the current character is: E or e, there cannot be two E's at the same time. There must be a number after E/e;

(4) Numbers other than 0~9 cannot appear in the current character.
Three state variables can be defined to record +/-.Status of E/e.

public class Solution {
    public boolean isNumeric(char[] str) {
        boolean hasSign=false;//Whether + and -
        boolean hasDecimal=false;//Whether decimal points have occurred;
        boolean hasE=false;//Has E occurred
        for(int i=0;i<str.length;i++){
            //There are three main situations:
            //1. Appearance + - 
            //2.Appear.
            //3. Emergence of E
            //4. Numbers
            if(str[i]=='+' || str[i]=='-'){
                //If the + sign is not the first occurrence, it must appear after E or e
                if(hasSign && str[i-1]!='E' && str[i-1]!='e'){
                    return false;
                }
                //First occurrence, must appear first
                if(!hasSign && i>0 && str[i-1]!='E' && str[i-1]!='e'){
                    return false;
                }
                hasSign=true;
            }else if(str[i]=='.'){
                //You cannot have two.
                if(hasE ||  hasDecimal){
                    return false;
                }
                hasDecimal=true;
               
            }else if(str[i]=='E' || str[i]=='e'){
                //E or e cannot recur
                if(hasE){
                    return false;
                }
                //E cannot appear in the last digit, followed by a number or + -
                if(i==str.length-1){
                    return false;
                }
                hasE=true;
            }else if(str[i]<'0' || str[i]>'9'){
                return false;
            }
         
        }
        return true;
    }
}

Left-handed K-bit string operation

Title Description:

Find the first character that appears only once in a string (0<=string length<=10000, all composed of letters) and return its position, or - 1 if not (case sensitive). (Count from 0)

Method 1:

Using a queue, the characters in the string are queued, and n characters from the beginning of the queue are put at the end.

import java.util.*;
public class Solution {
    public String LeftRotateString(String str,int n) {
       if(str.length()==0){
           return "";
       }
       Queue<Character> queue=new LinkedList<Character>();
       StringBuilder res=new StringBuilder();
       for(int i=0;i<str.length();i++){
           Character ch=str.charAt(i);
           queue.offer(ch);
       }
       int count=0;
       while(count++<n){
           queue.offer(queue.poll());
       }
       while(!queue.isEmpty()){
           res.append(queue.poll());
       }
        return res.toString();
    }
}

Method 2:

 import java.util.*;
public class Solution {
    public String LeftRotateString(String str,int n) {
        int len = str.length();
        if(len == 0) return "";
        n = n % len;
        str += str;
        return str.substring(n, n+len);
    }
}

Regular Expression Matching Problem

Title Description:

Implement a function to match regular expressions that include'.'and'. Characters in a pattern'.'denote any character, and''denotes that the characters preceding it can occur any number of times (including 0 times). In this case, matching means that all characters in a string match the entire pattern. For example, the string'a a A' matches the patterns'a.a'and'abaca', but it matches'a a.a' and'abaca'."ab*a" does not match

Solving ideas:

If this question is rigid and there are many situations, you can use the recursive idea to compare characters one by one. The core of recursion is to compare whether the current characters match or not. Under the condition of guaranteeing the current character match, the next character is matched. Due to the uncertainty of the position of'*'and'.', we need to discuss the classification:

(1) Judging that the current first=str[i] = =pattern[j] || pattern[j]=='.', so res=fist && str[i+1:]? Pattern[j+1:];

(2) when judging str [i+1:] and pattern [j+1]
(2.1) If pattern [j+1]=='*'&& j+1< pattern.length * matches 0 characters, continue comparing patterns [j+2]==str[i]

(2.2) Repeat at least one time with assurance first In case of matching, you also need to ensure pattern[j]==str[ i+1];  

(3) In the case of 2 unsuccessful cases (without * and.), it is necessary to judge first && str[i+]==pattern[j+1]

class Solution {
    boolean[][] dp;
    public boolean isMatch(String s, String p) {
        dp=new boolean[s.length()+1][p.length()+1]; 
        return  match(0,0,s,p);
    }

/**
*i: text Index of
*j: pattern Index of
**/
boolean match(int i,int j,String text,String pattern){
	boolean res;//Save matching results for character channeling
	if(j==pattern.length()){//Recursive End Conditions
		res = i==text.length();
	}else{
		//If the character in the current pattern is'.', the matching of the current character must be true
		//Otherwise, retrieve whether the corresponding characters in text and pattern are equal
		boolean curMatch=i<text.length()&&(text.charAt(i)==pattern.charAt(j) || pattern.charAt(j)=='.');
		//There are two cases to deal with: whether pattern[j+1] contains'*';
		if(j+1<pattern.length() && pattern.charAt(j+1)=='*'){
			//When included, there are two situations
			//Case 1:'*', repeat 0 previous characters, regardless of the current character and the previous character, i.e. compare text[i]?=pattern[j+2];
			//Case 2:'*', repeat multiple characters, then judge curMatch and text[i+1]?=pattern[j]; if mismatched, no matter how heavy
			//All strings will fail
			 res = match(i, j + 2, text, pattern) || curMatch && match(i + 1, j, text, pattern);
		}else{
			//Match next directly when not included
			 res = curMatch && match(i + 1, j + 1, text, pattern);
		}
	}
	dp[i][j]=res?true:false;//Maintain a dynamic planning table
	return res;
 }
}

Regular expression 2:

Description of the problem: In computers, wildcards are a special syntax widely used in file search, database, regular expression and other fields. Now you are required to implement the algorithm of string wildcards.
Requirement:

Implement the following two wildcards:

*: Match 0 or more characters (characters consist of letters and numbers 0-9, case-insensitive. Same below)

?: Match 1 character

Consistent with the idea of problem solving, note that the question does not repeat the previous characters, but matches any characters

import java.io.*;

public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String str="";
        while((str=br.readLine())!=null){
            String text=br.readLine();
            boolean res=match(0,0,text,str);
            if(res){
                System.out.println("true");
            }else{
                System.out.println("false");
            }
        }
    }
    public static boolean match(int i,int j,String text,String pattern){
        boolean res;//Save matching results for character channeling
        if(j==pattern.length()){//Recursive End Conditions
            res = i==text.length();
        }else{
            //If the character in the current pattern is'?', the matching of the current character must be true
            //Otherwise, retrieve whether the corresponding characters in text and pattern are equal
            boolean curMatch=i<text.length()&&(text.charAt(i)==pattern.charAt(j) || pattern.charAt(j)=='?');
            //There are two cases to deal with: whether pattern[j+1] contains'*';
            if(j+1<pattern.length() && pattern.charAt(j+1)=='*'){
                //When included, there are two situations
                //Case 1:'*', matches 0 characters, text[i+1] and pattern[j+2];
                //Situation 2:'*', matching multiple characters, and text[i+2]?=pattern[j+2];If mismatched, no matter how heavy
                //All strings will fail
                 res = curMatch && (match(i + 2, j+2, text, pattern) || match(i + 1, j+2, text, pattern)) ;
            }else{
                //Match next directly when not included
                res = curMatch && match(i + 1, j + 1, text, pattern);
            }
        }
        return res;
    } 
}

String to Integer

Title Description:

Converting a string to an integer requires a library function that cannot convert integers using a string. A value of 0 or a string that is not a valid value returns 0

Solving ideas:
(1) + or - Either not, there must be at str[0];

(2) Start with str[1:], check each character, res+=res*Math.pow(1,str.length-1-i);

(3) Finally, if res is an integer, it should be <=Integer.MAX_VALUE;Negative numbers require >=Integer.MIN_VALUE

(4) Note a special judgment that returns 0 when STR is null or'.equals'(str);

import java.util.*;
public class Solution {
    public int StrToInt(String str) {
        if(str.length()==0 || str.equals("")){
            return 0;
        }
        boolean isPostive=true;
        int res=0;
        for(int i=0;i<str.length();i++){
            char ch=str.charAt(i);
            if(i==0){
                if(ch=='+'){
                    isPostive=true;
                }else if(ch=='-'){
                    isPostive=false;
                }else if(!isNumric(ch)){
                    return 0;
                }else{
                    res+=(ch-'0')*Math.pow(10,str.length()-i-1);
                }
            }else{
                if(isNumric(ch)){
                    res+=(ch-'0')*Math.pow(10,str.length()-i-1);
                }else{
                    return 0;
                }
            }
        }
        if(isPostive && res<=Integer.MAX_VALUE){
            return res;
        }
        if(!isPostive && -1*res>=Integer.MIN_VALUE){
            return -1*res;
        }
        return 0;
        
    }
    private boolean isNumric(char c){
        if(c<'0' || c>'9'){
            return false;
        }
        return true;
    }
}

Poker card sequence

Description of the problem:

Essential description: 0 can replace any number, given five numbers randomly, they can form a strictly increasing sequence, where the number of 0 will not exceed 4;

Solving problems

(1) Sort arrays from smallest to largest

(2) Number of zeroNums calculated for 0

(3) Comparing from non-zero numbers, the adjacent two numbers cannot be the same; the difference between the adjacent two numbers minus 1 must be less than or equal to zeroNumm, so that 0 can fill the gap between them, while the remaining 0 can continue to fill the next round, note that I should be < numbers.length-1 at this time;This ensures that i+1 does not exceed the index.

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        //Special Judgment
        if(numbers.length!=5){
            return false;
        }
        //Be sure to sort
        Arrays.sort(numbers);
        int zeroNum=0;
        //Number of zeros calculated
        int i=0;
        while(i<numbers.length && numbers[i]==0){
            zeroNum++;
            i++;
        }
        //Here i points to the first non-zero number
        for(;i<numbers.length-1;i++){
            //No pairs can appear
            if(numbers[i]==numbers[i+1]){
                return false;
            }
            //The two values need to differ by 1, which can be supplemented by 0.
            if(numbers[i]+zeroNum>=numbers[i+1]-1){
                //The difference between numbers[i+1] and numbers[i]+1 cannot exceed zeroNum, otherwise it cannot be filled back
                zeroNum-=numbers[i+1]-1-numbers[i];//Calculate remaining zeroNum
            }else{
                return false;
            }
        }
        if(i==numbers.length-1){
            return true;
        }else{
            return false;
        }
        
    }
}

Flip words in a sentence

Title Description:

For example,'student. a am I'. Later, I realized that this guy had reversed the order of the words in the sentence. The correct sentence should be'I am a student'.

Pay special attention to one detail

"And" is a different string, so use str.trim().equal(") to have it output as is

public class Solution {
    public String ReverseSentence(String str) {
        StringBuilder res=new StringBuilder();
        if(str==null ){
            return null;
        }
        if(str.trim().equals(" ")){
            return str;
        }
        String[] strs= str.split(" ");
        for(int i=strs.length-1;i>=0;i--){
            if(i==0){
                res.append(strs[i]);
            }else{
                res.append(strs[i]);
                res.append(" ");
            }
        }
        return res.toString();
    }
}

Rotate String Problem (Difficult)

Description of the problem:

A string can be decomposed into multiple binary trees. If the str length is 1, it is considered not decomposable; if the str length is N (N>1),The left half can be 1~N-1 in length, the right half can be the remaining length, and then you can swap the left and right parts. And the left and right parts can continue to decompose according to the same logic. Each formed string can be a rotated string of the original string. Now give you two strings, STR 1 and str2, to determine if STR2 is a rotated string of STR 1.
Solving ideas:

Look directly at the picture
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-bmg22U1n-1633614916547)(./img/rotation string.png)]
Reference Code

import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String s1=br.readLine();
        String s2=br.readLine();
        if(helper(s1,s2)){
            System.out.print("YES");
        } else{
            System.out.print("NO");
        }
    }
    
    //Determines whether the character type and length are the same in two strings
    private static  boolean isSameChar(char[] str1,char[] str2){
         if (str1.length != str2.length) {
            return false;
        }
        int[] map = new int[256];
        for (int i = 0; i < str1.length; i++) {
            map[str1[i]]++;
        }
        for (int i = 0; i < str2.length; i++) {
            if (--map[str2[i]] < 0) {
                return false;
            }
        }
        return true;
    }
    //The types and lengths of str1 and str2 are the same
    //Determine if they are rotated strings
    //Whether str1[i,i+size) and str[j,j+size) are spin strings
    private static boolean isScrambel(char[] str1,char[] str2,int L1,int L2,int size){
        if (size == 1) {
            return str1[L1] == str2[L2];
        }
        // Enumerate all cases, return true if one is satisfied
        for (int leftPart = 1; leftPart < size; leftPart++) {
            if((isScrambel(str1, str2, L1, L2, leftPart) && isScrambel(str1, str2, L1 + leftPart, L2 + leftPart, size - leftPart)) || (isScrambel(str1, str2, L1, L2 + size - leftPart, leftPart) && isScrambel(str1, str2, L1 + leftPart, L2, size - leftPart))) {
                return true;
            }
        }
        return false;
    }
    private static boolean isScramble2(char[] s1, char[] s2) {
        int N = s1.length;
        boolean[][][] dp = new boolean[N][N][N + 1];
        // Initially fillable position
        for (int L1 = 0; L1 < N; L1++) {
            for (int L2 = 0; L2 < N; L2++) {
                dp[L1][L2][1] = s1[L1] == s2[L2];
            }
        }
    // Remaining locations
    // The first layer for loop is filled with layers size=2, 3,..., N in turn, one two-dimensional plane for each layer
        for (int size = 2; size <= N; size++) {
            // The second and third for cycles fill this two-dimensional plane
            for (int L1 = 0; L1 <= N - size; L1++) {
                for (int L2 = 0; L2 <= N - size; L2++) {
                    // Layer 4 for loop corresponds to recursive function content
                    for (int leftPart = 1; leftPart < size; leftPart++) {
                        if((dp[L1][L2][leftPart] && dp[L1 + leftPart][L2 + leftPart][size - leftPart]) || (dp[L1][L2 + size - leftPart][leftPart] && dp[L1 + leftPart][L2][size - leftPart])) {
                            dp[L1][L2][size] = true;
                            break;
                        }
                    }
                }
            }
        }
       return dp[0][0][N];
    }
    private static boolean helper(String s1,String s2){
        if ((s1 == null && s2 != null) || (s1 != null && s2 == null)) {
            return false;
        }
        if (s1 == null && s2 == null) {
            return true;
        }
        if (s1.equals(s2)) {
            return true;
        }
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        if(!isSameChar(str1,str2)){
            return false;
        }
        return isScramble2(str1,str2);
    }
}

Because of the high time complexity of the above steps, you can change the above functions into dynamic programming and set up a three-dimensional dynamic programming table, dp[L1][L2][len+1], to indicate that the L1 position of STR 1 begins to intercept len position, and the L2 position of str2 begins to intercept cold len position; at the same time, you need to master a small technique to determine whether two strings are equal.

Array problem

Build product array

Title Description:

Givean array A[0,0,1,............, n-1], please build an array B[0,1,..., n-1], B[0,1,..., n-1], where B[[i]=A[[0]* A[[[1]* *A[[[[[[1]*...*A [i-1] *A[[[[*i-1] *A[[i+i+1] [[[I+I+1] [[[A[[[0]]]]] [A [0] = A [1] = A [1]] = A [A [1]] * A[[A[[1] [[A [A [A [0, 1]] [[A [A [0, 1]] [n-2];)

Title Analysis:

It is observed that the result of B[i] is the product of element A[i] removed from A[0:length-1].

public class Solution {
    public int[] multiply(int[] A) {
        int[] B=new int[A.length];
        for(int i=0;i<B.length;i++){
            B[i]=1;
        }
        for(int i=0;i<B.length;i++){
            for(int j=0;j<A.length;j++){
                if(i==j){
                    continue;
                }
                B[i]*=A[j];
            }
        }
        return B;
    }
}

Repeated numbers in an array

Title Description:

The size of the elements in an array with length n is 0~n-1. Determine if there is a duplicate element in the element and output the element to an array duplication [0]

Solving ideas:

Set an array of counts [] to record the number of each element, and then iterate through the count array. If you find count [number[i]]>=2, assign the number[i] to duplication[0], which is essentially an array used in java to simulate output elements.

public class Solution {
    // Parameters:
    //    Number:Input Array
    //    Length: Enter the length of the array
    //    duplication: An output array that records any duplicate number found
    // Return value: True if found, False otherwise                    
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length==0){
            return false;
        }
        int[] count=new int[length];
        for(int i=0;i<length;i++){
            count[numbers[i]]++;
        }
        for(int i=0;i<count.length;i++){
            if(count[numbers[i]]>=2 ){
                duplication[0]=numbers[i];
                return true;
            }
        }
        return false;
    }
}

And two numbers for sum

Description of the title:

Enter an incrementally ordered array and a number S. Find two numbers in the array so that their sum is exactly S. If the sum of more than one number equals S, the product of the output two numbers is the smallest.

Solving ideas:

Since the array is already ordered, setting the left pointer to the head of the array and the right pointer to the end of the array will clamp them in opposite directions. There are three situations in clamping.

(1) arr[left]+arr[right]==sum, indicating that the greater the difference between the two numbers, the smaller the product, so as long as it is found, this value must meet the minimum product requirements.

(2) arr[left]+arr[right]>sum, which needs to be added to one of the additions, can only be left++ (because the array is increasing);

(3) arr[left]+arr[right]< sum, need to reduce an additive, can only be right-

//Following the analysis above, the code here can be directly added to the returned set by finding the left and right that meet the requirements, but here is a step of judgment. For reference only.
import java.util.ArrayList;
public class Solution {
   public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
       ArrayList<Integer> res=new ArrayList<Integer>();
       if(array.length<2){
           return res;
       }
       int left=0;
       int right=array.length-1;
       int s=0;
       int minNum1=-1;//Record the left corresponding to the minimum product;
       int minNum2=-1;//Record the right corresponding to the minimum product;
       int min=Integer.MAX_VALUE;//Initial minimum.
       while(left<right){
           s=array[left]+array[right];
           if(s<sum){
               left++;
           }else if(s>sum){
               right--;
           }else{
               if(array[left]*array[right]<=min){
                   min=array[left]*array[right];
                   minNum1=left;
                   minNum2=right;
               }
               left++;//Keep looking for the next pair
               right--;
           }
       }
       //Only the smallest will enter the result set.
       if(minNum1>=0 && minNum2>=0){
           res.add(array[minNum1]);
           res.add(array[minNum2]);
       }
       
       return res;
   }
}

Only one element in the array is repeated

Title Description:

Array size is n+1, its elements are 1~n, only one element repeats, other elements appear once, please design an algorithm to find out this element.

Solving ideas:

Use the XOR operator. It has three properties

(1)n^n=0

(2)n^0=n

(3) satisfying the exchange law, a bc=a(bc)

Based on the above three properties, we can design the following algorithm, assuming n=1000, that is, n is found in an array of {1,2,3,..., n,... 1000}.

  • Set T=123...n n...1000=123...^1000 (removes duplicate element n)
  • Set Q=123...n...^1000 (contains only one n)
  • According to the operation rules, T^Q=n;
    From the above formula we can write the following code
class Solution{
    public int finDifferent(int[] arr){
        int T=0;
        int Q=0;
        //T=1^2^3^...^n^n^...^1000
        for(int i=0;i<arr.length;i++){
            T ^= arr[i];
        }
        //Q=1^2^3^...^n^...^1000
        for(int i=1;i<arr.length;i++){
            Q^=i;
        }
        return T^Q;
    }
}

Two numbers that appear only once in the array

Title Description:

In an array, only two numbers are not duplicated, and the rest are duplicated once. Design an algorithm to find out which two numbers are not duplicated.

Solving ideas:

This question is solved in the same way as the core idea of the previous one. Let's take number=[1,2,2,3,3,4] as an example.

  • Set T=122334=14
  • If number s can be divided into two subarrays a=[1,3,3] and b=[4,2,2], then we can use Ta=14(122)=4 and Tb=14(4,3,3)=1
  • The key is how to divide the number into arrays a and b?
    Since T=14 (two numbers are different, T must not be zero) is converted to binary, at least one bit (N) is 1, and the N-bit of binary 1 and 4 must be different (according to the rules of operation), then the array can be divided into two groups based on whether the N-bit of binary is 1. The possible result of the division in the previous case is a=[1, 3,3] b=[2, 4,4], and the last 133=1 244=4,Get the final result.
//num1,num2 are arrays of length 1, respectively. Outgoing parameter
//Set num1[0],num2[0] to return results
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int T=0;
        //Result of all numbers ^
        for(int i=0;i<array.length;i++){
            T^=array[i];
        }
        //Find Bit 1 in Binary in T
        int index=findOneBit(T);
        //Traverse the array and group
        num1[0]=0;
        num2[0]=0;//0^n=n
        for(int i=0;i<array.length;i++){
            if(isBitOne(array[i],index)){
                //Group a, iterate with T^
                num1[0]^=array[i];
            }else{
                num2[0]^=array[i];
            }
        }
    }
    //Find an index of num's binary bit 1,
    //For example: 00100 returns 2
    private int findOneBit(int num){
        int index=0;
        while(( num & 0x1)==0){
            num=num >> 1;
            index++;
        }
        return index;
    }
    //Determine if the index bit of num is 1
    private boolean isBitOne(int num,int index){
        //Move num left index bit and then &0x1
        num=num >> index;
        return (num & 0x1)==1?true:false;
    }
}

Ordered Array Statistics

Title Description:

Counts the number of specified values in an ordered array, requiring a time-complex bit logn

Solving ideas:

When you see the logn, conditional reflection thinks of the dichotomy, but there's only a small improvement. After finding k==array[mid], you can't go back immediately. You should continue to look left and right at this point. Current count+1, left or right, is count++.
(1) The left boundary cannot be < 0, and the right boundary cannot be > arr.length-1

public class Solution {
    public int GetNumberOfK(int [] array , int k) {
       int count=0;
       int l=0;
       int r=array.length-1;
       while(l<=r){
           int mid=(l+r)/2;
           if(array[mid]>k){
               //Left Half Region
               r=mid-1;
           }else if(array[mid]<k){
               l=mid+1;
           }else{
               //The current mid conforms, count+1;
               count++;
               //Continue scanning to the left of mid
               int tmp=mid-1;
               while(true){
                   if(tmp<0 || k!=array[tmp]){
                       break;
                   }
                   count++;
                   tmp--;
               }
               //Continue scanning to the right to find
               tmp=mid+1;
               while(true){
                   if(tmp>array.length-1 || k!=array[tmp]){
                       break;
                   }
                   count++;
                   tmp++;
               }
               return count;
           }
       }
       return 0;
    }
}

Place odd numbers before even numbers

Title Description:

Enter an array of integers and implement a function to adjust the order of the numbers in the array so that all odd numbers are in the first half of the array and all even numbers are in the second half of the array, keeping the relative positions between odd and odd numbers and even numbers unchanged.

Solving ideas:

Solution for Reference Insert Sorting

(1) From the second odd number, refer to the insertion sort method, insert the odd number into the first even number position before the odd number.

(2) the insertion process, referring to the insertion sort code.

public class Solution {
    public void reOrderArray(int [] array) {
        int len=array.length;
        int i=0;
        while(i<len){
            if(array[i]%2==0){
                i++;
            }else{
               //If odd, array[j] is odd
                if(i==0){
                    i++;
                    continue;
                }
                //From the second number, insert the current odd number into the previous even number position
                //This code refers to the insertion sort code
                int j=i;
                int tmp=array[i];
                while(j-1>=0 && array[j-1]%2==0){
                   array[j]=array[j-1];
                   j--;
                }
                //At this point, j points to the first even-numbered position. The current odd number is inserted there
                array[j]=tmp;
                //Continue traversal
                i++;
            }
        }
    }
}

Print Matrix Clockwise

Title Description:

Enter a matrix to print out each number in clockwise order from outside to inside. For example, if you enter the following 4 X 4 matrix: 1 2 3 4 5 6 7 9 11 12 13 14 15 16, the numbers 1,2,3,4,8,12,16,14,13,9,5,7,11,10 will be printed out sequentially.

Solving ideas:

Set up, down, left, right to complete the traversal of up boundary to the right, right boundary to the down, right boundary to the left, and left boundary to the left, respectively. For each traversal of the left boundary, the corresponding boundary is removed and left<=right is required.Up<=down; the program completes clockwise printing in such a way that the boundaries are gradually reduced.

Enjoy a piece of code directly

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        //Special judgment, row, column, itself is empty, all return null value.
        if(matrix.length==0 || matrix[0].length==0 || matrix==null){
            return res;
        }
       //Define four boundaries left, right, up, down
        int left=0;
        int right=matrix[0].length-1;
        int up=0;
        int down=matrix.length-1;
        while(true){
            //Top row, scan right, col++;
            for(int col=left;col<=right;col++){
                res.add(matrix[up][col]);
            }
            //Remove the top row, up--;
            up++;
            //Can't go beyond the boundary
            if(up>down){
                break;
            }
            
            //Scan down the rightmost column, row+.
            for(int row=up;row<=down;row++){
                res.add(matrix[row][right]);
            }
            right--;
            if(right<left){
                break;
            }
            
            //Scan the last line to the left
            for(int col=right;col>=left;col--){
                res.add(matrix[down][col]);
            }
            down--;
            if(down<up){
                break;
            }
            
            //Scan up the leftmost column
            for(int row=down;row>=up;row--){
                res.add(matrix[row][left]);
            }
            left++;
            if(left>right){
                break;
            }
        }
        return res;
    }
}

More than half of the elements in the array

Title Description:

There is a number in the array that occurs more than half the length of the array. Find out this number. For example, enter an array {1,2,3,2,2,5,4,2} with a length of 9. Since number 2 appears five times in the array, more than half the length of the array, output 2. If it does not exist, output 0.

Solving ideas:

Candidate rule, Core principle: Same element rule + 1, different rule - 1, if more than half, then the final counter must be > 1,

(1) Initialize a candidate and give it a vote

(2) count+1 for each occurrence of the candidate in the array; count-1 for each absence indicating that the vote was given to another person;

(3) When the number of votes becomes zero again, the current element is elected.

(4) Check the number of occurrences of the last candidate, if more than half of them are output, otherwise 0 is output;

Look at a piece of code and see everything. All text explanations seem pale.

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        //Adopt Candidate Law
        int con=-1;//Candidate
        int count=0;//Number of votes
        //A ticket can only be given to one person.
        for(int i=0;i<array.length;i++){
            if(count==0){//If the number of votes is zero, the current element is elected as the candidate and the votes are obtained.
                con=array[i];
                count++;
            }else{
                //Later candidates get votes
                if(con==array[i]){
                    count++;
                }else{
                    count--;
                }
            }
        }
        //After a round of voting, candidates can be found
        count=0;
        //Count the votes for the candidate
        for(int i=0;i<array.length;i++){
            if(con==array[i]){
                count++;
            }
        }
        //More than half output candidates
        return count>array.length/2?con:0;
    }
}

TopK Question

Title Description:

Find the minimum number of k from the array

Problem solving analysis:

This is a typical topK problem, using priority queue to simulate the big top heap, the big top heap has the following characteristics: Every element queued is the largest element, using this feature, we can set up a large top heap with the capacity of K, queue k elements according to the order of the array, and then compare the following elements with the elements in the big top heap, replace the smallest elements with the largest ones in the big top heap, so we can operateBy doing so, you can ensure that the elements in the top heap are relatively small.

Note that in jdk1.8, PriorityQueue defaults to a small top pair, passing in a capacity and comparator that can be implemented using lamaba expressions, (o1,o2) ->o2-o1 for the large top heap.

import java.util.*;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
       ArrayList<Integer> result = new ArrayList<Integer>();
       int length = input.length;
       if(k > length || k == 0){
           return result;
       }
        //Big Top Heap: Each outgoing queue is the largest element, (o1,o2) -> (o2-o1);
        PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k,(o1,o2)->o2-o1);
        for (int i = 0; i < length; i++) {
            if (maxHeap.size() != k) {
                maxHeap.offer(input[i]);
            }else{
                if(maxHeap.peek() > input[i]){
                    maxHeap.poll();
                    maxHeap.offer(input[i]);
                }
            }
        }
        for (Integer integer : maxHeap) {
            result.add(integer);
        }
        return result;
    }
}

Maximum Sum of Continuous Subarrays

Description of the problem:
Given an array, find a continuous subarray to make its maximum.

Solving ideas:
Method 1:

Dynamic programming, where dp[i] represents the maximum sum of elements tailed by i, the steps for dynamic programming are:

(1) Determine the meaning of dp[i]

(2) determine base_case:dp[0]=array[0];

(3) Determine the state: maximum sum

(4) Enumerate the choices and choose the best one: Choose 1 as: dp[i-1] is a positive number, that is, dp[i-1]+array[i];Choose 2 for: dp[i-1] is negative, that is, dp[i]=array[i];Finally, the maximum max(dp[i-1]+array[i],array[i]) is obtained.

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int[] dp=new int[array.length];
        //base_case;
        dp[0]=array[0];
        int res=array[0];
        for(int i=1;i<array.length;i++){
            //Make a choice
            //Select 1:array[i] is a positive number, add array[i], then dp[i]=dp[i-1]+array[i];
            //Selection 2:array[i] is negative;
            dp[i]=Math.max(dp[i-1]+array[i],array[i]);
            res=Math.max(res,dp[i]);
        }
        return res;
    }
}

Method 2:

Set a contribution value, each element traversed, and heuristically add array[i]. If sum is negative, it is clear that elements ending in I do not contribute to the whole result, then set the contribution value of this element to 0, otherwise contribute, add the contribution value.

Finally, determine if the overall contribution value is 0, and if so, the largest element in the entire array is the sum of the largest subarrays;

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int res=array[0];
        int con=0;//Initialize contribution value
        for(int i=0;i<array.length;i++){
            if(con+array[i]<0){
                //Negative contribution value is zero, not included
                con=0;
            }else{
                con+=array[i];
                res=Math.max(con,res);
            }
        }
        if(con!=0){
            //Contribution is not zero;
            return res;
        }
        //Contribution 0
        res=array[0];
        for(int i=0;i<array.length;i++){
            res=Math.max(array[i],res);
        }
        return res;
    }
}

Combine the numbers in the array into the smallest number

Title Description:

Enter a positive integer array, stitch together all the numbers in the array into a single number, and print the smallest of all the numbers that can be stitched together. For example, enter the array {3, 32, 321}, and print out the smallest number that can be structured out of these three numbers is 32123.

Solving ideas:

It is essentially a sorting process, but the rules of sorting need to be changed. For example, for {a,b}, there are two cases according to the title requirements:

(1) "a b" > "b a", then the order is: B a

(2) "a b" < "b a", then the order is: a B

(3) "ab" = "ba", then the order of sorting is arbitrary.

In java, the java.util.Collections toolkit has a sort(List,Comparator) method that allows lists to be compared against incoming Comparators, and we make these logical judgments in this Comparator;

Usage of Comparator:

There is an int compare(O1,O2) method inside which the return value determines how O1 and O2 are sorted. If the number returned < 0 is false, the original order does not need to be adjusted. If the number returned < 0 is O1, the original order needs to be adjusted.

Direct Code

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Solution {
    public String PrintMinNumber(int [] numbers) {
        StringBuilder sb=new StringBuilder();
        ArrayList<Integer> list=new ArrayList<Integer>();
        for(int i=0;i<numbers.length;i++){
            list.add(numbers[i]);
        }
        Collections.sort(list,new Comparator<Integer>(){
            @Override
            public int compare(Integer o1,Integer o2){
                String str1=o1+""+o2;
                String str2=o2+""+o1;
                //a  b
                //A b>b a should be b a
                //ab<ba a b
                // ab==ba 0
                int res=str1.compareTo(str2);//str1-str2
                if(res>0){
                    return 1;//a and b need to be exchanged
                }else if(res<0){
                    return -1;
                }else{
                    return 0;
                }
            }
        });
        for(Integer e:list){
            sb.append(e);
        }
        return sb.toString();
    }
}

Inverse Order Pair Problem in Array

Title Description

Two numbers in an array that make up an inverse pair if the first number is greater than the last. Enter an array to find the total number P of the inverse pairs in the array. Output the result of modelling P to 1000000007. That is, output P%1000000007

Solving ideas:

According to the improvement of merge sort, in the merge sort process, two subarrays [a, b, c] [d, e, f], if a > d, need to put d into the cache array first, at the same time (a,d) is an inverse order pair, and B and C can form an inverse order pair.

It's easier to understand by looking directly at the explanations in the code

public class Solution {
    int res=0;
    public int InversePairs(int [] array) {
        if(array.length<2){
            return 0;
        }
        int[] tmp=new int[array.length];
        mergeSort(array,0,array.length-1,tmp);
        return res;
    }
    //Recursive division until l==r (only one element)
    private void mergeSort(int[] array,int l,int r,int[] tmp){
        if(l>=r){
            return ;
        }
        //Halve and divide, find mid first
        int mid=(l+r)/2;
        mergeSort(array,l,mid,tmp);
        mergeSort(array,mid+1,r,tmp);
        merge(array,l,mid,r,tmp);
    }
    private void merge(int[] array,int l,int mid,int r,int[] tmp){
        //The merging process
        //[l,mid] and [mid+1,r]
        int i=l;
        int j=mid+1;
        int k=0;
        while(i<=mid && j<=r){
            if(array[i]>array[j]){
                tmp[k++]=array[j++];
                //Core part, think key:
                //Array[i]>array[j] indicates that the two elements are in reverse order, and
                //[l,mid] and [mid+1,r] are already ordered, that is, array[mid]>array[l], so array[1...mid] is in reverse order
                //Quantity is mid-i+1
                res+=(mid-i+1);
                res=res%1000000007;
            }else{
                tmp[k++]=array[i++];
            }
        }
        //Two parts must be traversed first and the rest copied to tmp
        
         while(i<=mid){
            tmp[k++]=array[i++];
        }
        //Right half not copied
        while(j<=r){
            tmp[k++]=array[j++];
        }
        //Note that instead of starting at 0, it may start at l of the subarray being processed, or mid+1;
        k=0;
        int tmpLeft=l;
        while(tmpLeft<=r){
            array[tmpLeft++]=tmp[k++];
        }
    }
}

And a sequence of consecutive positive integers for Sum

Title Description:

Find all contiguous and Sum positive integer sequences and arrange the output from smallest to largest

Solving ideas:

Double pointer, because it is a continuous sequence of positive integers, is an equal difference column with a difference of 1, so curSum=( a 0 a_0 a0​+ a n a_n an) *n/2;Move the window by comparing the size of curSum and Sum. There are three cases:

(1) But curSum==sum, find, add all the data in the window to the result set, and move the window to the left.

(2) surSum< sum, the right side of the window is enlarged with an additional element,

(3) curSum>sum, the left window moves to the right, reducing one element,

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       //Using double pointers, continuous positive integers [1,2,...n]
       //Initialize window [1,2], with at least two elements.
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        
        int left=1;
        int right=2;
        while(left<right){
           int curSum=(left+right)*(right-left+1)/2;//Standard summation formula
            ArrayList<Integer> list=new ArrayList<Integer>();
           if(curSum==sum){
               //Add all the data in the window
               for(int i=left;i<=right;i++){
                   list.add(i);
               }
               res.add(list);
               left++;
           }else if(curSum<sum){
               //Right Window Move
               right++;
           }else{
               left++;
           }
        }
        return res;
    }
}

And is a subarray of K

class Solution {
    public int subarraySum(int[] nums, int k) {
        Map<Integer,Integer> map=new HashMap<>();
        int sum=0;
        int res=0;
        map.put(0,1);//It is very important that the number of subarrays initialized and 0 is 1
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];//Summation from left to right;
            if(map.containsKey(sum-k)){
                //If map contains sum-k, then the sum of the current element and its preceding elements is k
                //The result plus the number of sum-k
                res+=map.get(sum-k);
            }
            //If there is a sum value in the map, use its value, otherwise it is the default value;
            map.put(sum,map.getOrDefault(sum,0)+1);
        }        
        return res;
    }
}

Alphabetic Ectopic Word Grouping

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> map=new HashMap<>();
        for(String str:strs){
            char[] ch=str.toCharArray();
            Arrays.sort(ch);//This sorting must be the same in rank;
            String key=String.valueOf(ch);
            if(!map.containsKey(key)){
                map.put(key,new ArrayList<>());
            }
            map.get(key).add(str);
        }
        return new ArrayList(map.values());
    }
}

Shortest Unordered Array

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int len=nums.length;
        int max=Integer.MIN_VALUE;//Default to first element value
        int min=Integer.MAX_VALUE;//Default to last element value
        int high=0;
        int low=0;
        for(int i=0;i<nums.length;i++){
            //If sorted in ascending order, the current maximum is recorded, and if nums[i]<max, the I position needs to be adjusted
            max=Math.max(max,nums[i]);
            if(nums[i]<max){
                high=i;
            }          
            min=Math.min(min,nums[len-1-i]);
            if(nums[len-1-i]>min){
                low=len-1-i;
            } 
        }    
        return high>low?high-low+1:0;
    }
}

Mathematics-related problems

##Subset

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
        List<List<Integer>> res=new LinkedList<>();
        res.add(new LinkedList<>());
        for(int i=0;i<nums.length;i++){
            int s=res.size();
            for(int j=0;j<s;j++){
                List<Integer> list=new ArrayList<>(res.get(j));
                list.add(nums[i]);
                res.add(list);
            }
        }
        return res;
    }
}

Judgment of prime numbers

Solving problems
For each number n, it is not necessary to judge n-1 from 2. We know that if a number can be factored, then the two numbers must be one less than or equal to sqrt(n) and one greater than or equal to sqrt(n). Therefore, it is not necessary to traverse to n-1 and sqrt(n) in the above code, since no approximation can be found on the left side of sqrt(n).

 public boolean isPrimes(int num){
        int tmp=(int)Math.sqrt(num);
        for(int i=2;i<=tmp;i++){
            if(num%i==0){
                return false;
            }
        }
        return true;
    }

Hamming Distance

class Solution {
    public int hammingDistance(int x, int y) {
        int tmp=x^y;//Same 0, different 1;
        int count=0;
        while(tmp!=0){
            count+=tmp&1;//Judge the lowest bit
            tmp=tmp>>1;//Move two to the right;
        }
        return count;
    }
}

Add without adding

Title Description:

Solving the addition of two integers without the + - * / operator

Solving ideas:

Convert two integers into binary num1 and num2;

(1) The result of adding two binary bits, i.e. int sum=num1^num2, regardless of the carry condition;

(2) Solve the carry of the addition of two numbers by moving them one bit to the left, that is, int carry=(num1&num2)< < 1;

(2) The results of the above two steps are calculated again in a loop until carry carry is zero.

public class Solution {
    public int Add(int num1,int num2) {
        while(num2!=0){
            int sum=num1^num2;//The addition of two numbers equals ^ regardless of carry
            int carry=(num1&num2)<<1;//Calculate carry, bitwise and move 1 bit to the left
            num1=sum;
            num2=carry;
        }
        return num1;
    }
}

Extensions:

Do not use + - * / do 1+2+3+4+...+n

In the same way, look directly at the code

public class Solution {
    public int Sum_Solution(int n) {
        int sum=0;
        for(int i=1;i<=n;i++){
            sum=add(sum,i);
        }
        return sum;
    }
    private int add(int num1,int num2){
        while(num2!=0){
            int sum=num1^num2;
            int carry=(num1&num2)<<1;
            num1=sum;
            num2=carry;
        }
        return num1;
    }
}

Counting

Title Description:

Given a float base of type double and an integer exponent of type int. Find the exponent power of base. Make sure that base and exponent are not equal to 0

Solving steps:

(1) Consider exponent as a positive number. From right to left, solve the exponent binary one by one, if the bit is 1, res*=res*base;Otherwise, the bit is zero, no calculation is required, go directly to the next bit

(2) For each bit calculated, the bit is discarded, that is, the operation >> 1

(3)base=base*base;

(4) If exponent is negative, the final result res=1/res;

public class Solution {
    public double Power(double base, int exponent) {
        boolean flag=exponent>0;
        double res=1;
        exponent=Math.abs(exponent);
        while(exponent!=0){
            if((exponent & 0x1)!=0){
                res*=base;
            }
            base*=base;
            exponent = exponent >>> 1;//Discard the lowest bit, and the next round of loops can do a direct & operation with 1.
        }
        if(flag){
            return res;
        }
        return 1/res;
    }
}

Number of 1 in integer binary

Solving ideas:

Starting with the highest bit, perform an &operation with flag=1, if 1 indicates the current bit is 1, the counter adds one, and you can falg=flag< 1 before going to the next loop, which is equivalent to moving 1 to the next highest bit. Loop the operation above again.

public class Solution {
    public int NumberOf1(int n) {
        int count=0;
        int flag=1;
        while(flag!=0){
            if((n & flag)!=0){
                count++;
            }
            flag=flag << 1;
        }
        return count;
    }
}

Number of clowns

Title Description:

Numbers that contain only prime factors 2, 3, and 5 are called Ugly Numbers. For example, 6 and 8 are ugly numbers, but 14 are not because they contain prime factor 7. We are accustomed to treating 1 as the first Ugly Number. Find the Nth Ugly Number in the order from smallest to largest.
Solving ideas:

By definition, the number of clowns must be: twice or three or five times the number of previous clowns. In order to arrange the number of clowns from childhood to childhood, the current number of clowns is selected according to one of the three cases above, so that the index-1 can be updated iteratively.

public class Solution {
    public int GetUglyNumber_Solution(int index) {
        if(index<=6){
            return index;
        }
        int[] res=new int[index];
        int t1=0;
        int t2=0;
        int t3=0;
        res[0]=1;//First Ugly Number
        for(int i=1;i<index;i++){
            res[i]=Math.min(res[t1]*2,Math.min(res[t2]*3,res[t3]*5));
            if(res[i]==res[t1]*2){
                t1++;
            }
            if(res[i]==res[t2]*3){
                t2++;
            }
            if(res[i]==res[t3]*5){
                t3++;
            }
        }
        return res[index-1];
    }
}

Binary Search

Rotate Array to Find Target

Idea 1: If the middle number is less than the rightmost number, the right half is ordered. If the middle number is greater than the rightmost number, the left half is ordered. We only need to use the first and last two arrays in the ordered half to determine if the target value is in this area, so that we can determine which side to keep.
**Idea two:**Divide an array into two, one of which must be ordered, the other may be ordered or partially ordered. At this point, the ordered part is searched by dichotomy. The disordered part is divided into two more, one of which must be ordered, the other may be ordered and possibly disordered. So loop.

class Solution {
    public int search(int[] nums, int target) {
        int len = nums.length;
        int left = 0, right = len-1;
        while(left <= right){
            int mid = (left + right) / 2;
            if(nums[mid] == target)
                return mid;
            else if(nums[mid] < nums[right]){
                if(nums[mid] < target && target <= nums[right])
                    left = mid+1;
                else
                    right = mid-1;
            }
            else{
                if(nums[left] <= target && target < nums[mid])
                    right = mid-1;
                else
                    left = mid+1;
            }
        }
        return -1;
    }
}

Rotate Array Find Minimum

Title Description:
Enter a rotated array to find the minimum value in the array, requiring a time complexity of (logn)

Title Analysis:

  • Rotated array: refers to moving the previous part of an ordered array to the latter part, such as [1,2,3,4,5] A rotated array is: [2,4,5,1,2]
  • Time Complexity logn: Immediately think of dichotomy (Half Search)
  • A fixed comparison value is usually needed for dichotomy, but this question does not exist. What should I do? There are several cases according to the specific analysis of the topic:
    (1) [4,5,6,1,2,3], arr[mid]>arr[first], so min is in the interval [mid+1,last]

(2) [4,5,1,2,3] arr[mid]< arr[last], so min is in the interval [first,mid]

(3) [1,1,1,0,1], then, first, move one bit to the left;

Code

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        if(array.length==0){
            return 0;
        }
        int i=0;//First element
        int j=array.length-1;
        while(i<j){
            if(array[i]<array[j]){
                return array[i];
            }
            int mid=(i+j)/2;
            if(array[i]<array[mid]){
                //The minimum value to find must be in the right half
                i=mid+1;
            }else if(array[j]>array[mid]){
                j=mid;
            }else{
                i++;
            }
        }
        //Special case: only one element
        return array[i];
    }
}

The total number of occurrences of finding 1 in an array of integers

Title Description:
Find the number of occurrences of 1 in 113 integers and the number of occurrences of 1 in 1001300 integers? For this reason, he specifically counted the number of occurrences of 1, 10, 11, 12, 13 in 1-13, so there were 6 occurrences in total, but he had no problem with the latter. ACMer wants you to help him and make the problem more general so that he can quickly find the number of occurrences of 1 in any non-negative integer range.(Number of occurrences of 1 in 1 to n).

Solving ideas:

The current value cur is taken from the lowest bit to the highest bit, and the high and low positions of cur are calculated.

When cur==0, the number of occurrences of 1 = high*i;

When cur==1, the number of occurrences of 1 = high*i+(low+1);

In other cases, the number of occurrences of 1=(high+1)*i;

Final sum from lowest to highest

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int count=0;
        for(int i=1;i<=n;i*=10){
            int high=n/(i*10);
            int low=n%i;
            int curVal=n/i%10;
            if(curVal==0){
                count+=high*i;
            }else if(curVal==1){
                count+=high*i+(low+1);
            }else{
                count+=(high+1)*i;
            }
        }
        return count;
    }
}

Finding values in a two-dimensional array

Title Description:
In a two-dimensional array (each one has the same length), each row is sorted in increasing order from left to right, and each column is sorted in increasing order from top to bottom. Complete a function by entering such a two-dimensional array and an integer to determine if the array contains the integer.

Title Analysis:

Start with the lower left element (curVal), which is the largest number in the row and the smallest number in the column. If target > curVal, you can only start looking in the next column, col++. If target < curVal, you can only look in the previous row, row-1; note col<=cols-1;Row>=0;

public class Solution {
    public boolean Find(int target, int [][] array) {
        //The middle value of the last column
        int rows=array.length;//Number of rows in a two-dimensional array
        int cols=array[0].length;//Number of columns in a two-dimensional array
        if(rows==0){
            return false;
        }
        if(cols==0){
            return false;
        }
        //Lower left quarter
        int row=rows-1;
        int col=0;
        while(row>=0 && col<=cols-1){
            if(array[row][col]<target){
                col++;
            }else if(array[row][col]>target){
                row--;
            }else{
                return true;
            }
        }
        return false;
    }
}

Move Zero

class Solution {
    public void moveZeroes(int[] nums) {
        int slow=0;
        //fast cannot stay on Zero
        for(int fast=0;fast<nums.length;fast++){
            if(nums[fast]!=0){//The fast pointer explores ahead to get non-zero numbers;
                nums[slow]=nums[fast];
                slow++;
            }
        }
        //Complement 0 for last element
        while(slow<nums.length){
            nums[slow++]=0;
        }
    }
}

Find repetitive numbers (with emphasis on reviewing their ideas)

class Solution {
    public int findDuplicate(int[] nums) {
         int left=0;
         int right=nums.length-1;
         while(left<right){
             int count=0;
             int mid=left+(right-left)/2;
             //Find the number <=mid
             for(int num:nums){
                 if(num<=mid){
                     count++;
                 }
             }
             //If there are no duplicates, count<=mid, so the number of duplicates must be [mid+1, right]
             if(count<=mid){//[left,mid]
                left=mid+1;
             }else{
                 right=mid;
             }
         }
         return right;
    }
}

Recursive problem

Motion Range of Robot

Title Description:

There is a square of m rows and n columns on the ground. A robot starts moving from a grid of coordinates 0,0 and can only move one grid in each of the four directions: left, right, up and down, but it cannot enter a grid where the sum of the number of row and column coordinates is greater than k. For example, when K is 18, the robot can enter a square (35,37) because 3+5+3+7 = 18. However, it cannot enter a square.(35,38) because 3+5+3+8 = 19. How many grids can the robot reach?

Problem solving analysis:

(1) Recursive solution, recursive end conditions: the sum of coordinate digits of the current grid > the set threshold, or not within the range of [0,rows-1] [0,cols-1], to avoid repeated searches, a flag[curRow][curRow] needs to be set to record that the current grid has been browsed.

(2) Implementation of the check() function. Use n%10 to get the lowest bit, n/10 to get integers except the lowest bit; loop through n=0 in turn until each bit is found

public class Solution {
    public int movingCount(int threshold, int rows, int cols){
        int[][] flag=new int[rows][cols];
        return movingCountHelper(threshold,rows,cols,0,0,flag);
    }
    private int movingCountHelper(int threshold,int rows,int cols,int curRow,int curCol,int[][] flag){
        //Special judgment, the current grid is not [0,rows] and [0,cols]
        if(curRow<0 || curRow>rows-1 || curCol<0 || curCol>cols-1 || flag[curRow][curCol]==1 || !check(curRow,curCol,threshold)){
            return 0;
        }
       flag[curRow][curCol]=1;//Setting the current grid has already passed;
       //Recursive search, left, right, up and down respectively.
       return 1+movingCountHelper(threshold,rows,cols,curRow,curCol+1,flag)
               +movingCountHelper(threshold,rows,cols,curRow,curCol-1,flag)
               +movingCountHelper(threshold,rows,cols,curRow+1,curCol,flag)
               +movingCountHelper(threshold,rows,cols,curRow-1,curCol,flag);
    }
    //Check current coordinates
    private boolean check(int row,int col,int threshold){
        int res=0;
        while(row!=0){
            res+=row%10;//Take the lowest position;
            row=row/10;//Remove the lowest digit;
        }
        while(col!=0){
            res+=col%10;
            col=col/10;
        }
        if(res>threshold){
            return false;
        }
        return true;
    }
}

Match string from matrix type

Title Description

Design a function to determine if there is a path in a matrix that contains all the characters of a string. The path can start with any grid in the matrix, and each step can move one grid to the left, right, up and down in the matrix.

Topic Analysis

Almost identical to the previous question, recursion + backtracking, recursion is essentially responsible for only your own work, the next logical step is the same as the current logic (call yourself)

(1) The function of recursive function is to determine whether the current coordinate position value is the same as the corresponding value in str. If it is the same, you can select either direction for recursive matching, which is reflected in the following recursion: the character in str is next;

(2) A variable visited[][] needs to be set to record whether the current grid has been visited or not.

(2) If the character in the current grid does not match the character in str[i], it needs to go back to the original state (visted[][]==flase) and set the current grid not to be browsed, that is, the operation of backtracking;

public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
        if(rows*cols<str.length){
            return false;
        }
        int[][] flag=new int[rows][cols];
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                if( pathHelper(matrix,rows,cols,i,j,str,0,flag)){
                    return true;
                }
            }
        }
        return false;
    }
    
    private boolean pathHelper(char[] matrix,int rows,int cols,int curRow,int curCol,char[] str,int curChar,int[][] flag){
        //Converting a two-dimensional array to a one-dimensional array
        int index=curRow * cols+curCol;
        if(curRow<0 || curRow>=rows || curCol<0 || curCol>=cols || flag[curRow][curCol]==1 || matrix[index]!=str[curChar]){
            return false;
        }
        //Complete string matching
        if(curChar==str.length-1){
            return true;
        }
        //Otherwise, the path can
        flag[curRow][curCol]=1;//Record that this road has been taken
        if(pathHelper(matrix,rows,cols,curRow-1,curCol,str,curChar+1,flag)
          || pathHelper(matrix,rows,cols,curRow+1,curCol,str,curChar+1,flag)
          || pathHelper(matrix,rows,cols,curRow,curCol+1,str,curChar+1,flag)
          || pathHelper(matrix,rows,cols,curRow,curCol-1,str,curChar+1,flag)
          ){
            return true;
        }
        //At this point, matching will fail, retrospectively
        flag[curRow][curCol]=0;//To flash back
        return false;
    }

}

Rectangular Coverage Problem

Title Description:

We can cover a larger rectangle with 21 small rectangles either horizontally or vertically. Please ask how many ways to cover a 2*n large rectangle with n 21 small rectangles without overlapping it.

Solving ideas:

public class Solution {
    public int RectCover(int target) {
       if (target < 1) {
            return 0;
        } else if (target == 1 || target == 2) {
            return target;
        } else {
           //target-1 represents the previous rectangle
            return RectCover(target-1) + RectCover(target-2);
        }
    }
}

Stepping Problem I

Description of the problem:

A frog can jump up one step at a time or two steps at a time... It can also jump up n steps. Ask the frog how many jumps there are in total on one n step.

Solving steps:

Violence enumeration: Set dp[i] to represent the number of jumps to the first order, then dp[n] is solved.

Initialization condition: dp[0]=dp[1]=1;

The core idea is that if you jump from level 1 to level I i, the upper level is i-1;
If the upper level jumps 2 steps to i, the upper level is i-2;

public class Solution {
    public int JumpFloorII(int target) {
        //dp[i], indicating the jump to step I
        //Calculate the number of jumps up step i before calculating the number of jumps from step i to target
        int[] dp=new int[target+1];
        dp[0]=1;//Jump up one step
        dp[1]=1;
        for(int i=2;i<=target;i++){
            //Enumerate jumps on i
            for(int j=0;j<i;j++){
                dp[i]+=dp[j];
            }
        }
        return dp[target];
    }
}

Stepping problem II

Title Description:

A frog can jump up either one or two steps at a time. Ask the frog how many jumps it takes to jump up an n-step (the order of which is different).

Solving ideas:

First analyze the problem:

Set: dp[i] represents the total jump to step I. Since only one or two steps can be jumped, the last step may only be I-1 or i-2, that is, dp[i]=dp[i-1]+dp[i-2];

Clearly, this is a dynamic planning problem:
base_case:dp[0]=1,dp[1]=1;

public class Solution {
    public int JumpFloor(int target) {
        int[] dp=new int[target+1];
        dp[0]=1;
        dp[1]=1;
        for(int i=2;i<=target;i++){
            dp[i]=dp[i-1]+dp[i-2];
        }
        //dp[target];
        return dp[target];
    }
}

Jumper connection problem III

Description of the problem:

Given a non-negative integer array, array elements indicate the maximum length you can jump at that location to determine if you can jump to the last position
For example: [2,3,1,1,4], you can jump 1 step from initial position 0 to position 1, then 3 steps and reach the last position, so you return to true

Solving steps:

You can use the greedy algorithm, and this topic can change the way you think: how far can you jump from position i? If this fast > n-1, you must jump to the last position

public class Solution {
    public int JumpFloor(int[] nums) {
        int fastest=0;
        for(int i=0;i<nums.length-1;i++){
            fastest=Math.max(fastest,i+nums[i]);
            if(fastest<=i){
                return false;
            }
        }
        //Array of length n, need to skip n-1 steps at most;
        return fastest>=n-1;
    }
}

Step Jump Problem IIII

On the basis of step problem III above, the minimum number of steps to reach the last position is determined.

Solving ideas:

Use the heart-to-heart algorithm, jump to the maximum position at each step, and then choose the largest position from this position to jump

public class Solution {
    public int JumpFloor(int[] nums) {
        int fastest=0;
        int end=0//Record the end of each jump
        int jump=0;
        for(int i=0;i<nums.length-1;i++){
            fastest=Math.max(fastest,i+nums);
            //Jump to the farthest position and count again
            if(i==end){
                jump++;
                end=fastest;//Update current fastest to global,
            }
        }
    }
}

Stack

Median problem in data flow

Title Description:

How do I get the median in a data stream? If I read odd numbers from a data stream, the median is the middle value after all the values are sorted. If I read even numbers from a data stream, the median is the average of the middle two values after all the values are sorted. We read the data stream using Insert() and GetMedian() Method Gets the median of the current read data.

Analysis of topics:

To use the PriorityQueue priority queue for this topic, let's first introduce the Priority Queue, which is a special queue, but when queuing, the elements that come out from the first queue have a priority (that is, always the maximum or always the minimum), which can be set:

  • New PriorityQueue ((a, b) ->a-b);Inside the queue is an ascending sort (default), that is, the element at the beginning of the queue is always the minimum of the current value, so it is minHeap;
  • New PriorityQueue ((a, b) ->b-a);Inside the queue is a descending sort, that is, the first element of the queue is the maximum, so it is: maxHeap;
    Because we don't know the data is added dynamically and the parity of the length of the data is uncertain, we can use a count to odd numbers. At the same time, to ensure that the data can be added to maxHeap and minHeap dynamically and evenly, we agree that when the count is odd, the data is added to maxHeap.Otherwise, to join minHeap, in order to ensure that the heads of maxHep and minHeap are median, we need to ensure that the elements num to be added must match: the first element of maxHeap <=num<=minHeap, can be understood by referring to the following figure:

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-yMw8J2CO-1633614916564)(./img/priority queue.png)]

As shown in the figure: The element to be inserted is 5, according to the above convention (odd insertion elements, inserted in maxHeap), you need to ensure that 5 is inserted into maxHeap and then conforms to: "the first element in maxHeap <=the first element in minHeap queue". If direct insertion is satisfied, you need to make the following adjustments:Five is inserted into minHep first(The minHeap will be automatically descending in order, at which point the elements of the minHeap queue head must meet the above conditions), even numbers, the same thing, specific reference code, better understanding

import java.util.*;
public class Solution {
    //Create a large top heap (for ascending sorting), lambada expression to implement a comparator comparer
    Queue<Integer> maxHeap=new PriorityQueue<Integer>((a,b)->b-a);
    Queue<Integer> minHeap=new PriorityQueue<Integer>((a,b)->a-b);
    //Total number of recorded data, odd and even processing separately
    //To ensure that the data is evenly distributed between the two heaps, it is agreed that count s are even
    //First enter maxHeap, otherwise enter minHeap; also ensure that the maximum element of maxHeap <=the minimum element in minHeap
    int count=-1;
    public void Insert(Integer num) {
        count++;
        if(count%2==0){//Even number into maxHeap, judgment before entering
            if(!minHeap.isEmpty() && num>minHeap.peek()){
                minHeap.add(num);
                num=minHeap.poll();
            }
            maxHeap.add(num);
        }else{//Odd Number
            if(!maxHeap.isEmpty() && num<maxHeap.peek()){
                //Ensure that the element num added to minHeap is not less than maxHeap.peek(), otherwise it will be exchanged
                maxHeap.add(num);
                num=maxHeap.poll();//Internal automatic ascending sort
            }
            minHeap.add(num);
        }
    }
    public Double GetMedian() {
        //Take out the same odd and even nature
        if(maxHeap.size()==minHeap.size()){
            //Take the average of the top elements of the two priority queues
            return (maxHeap.peek()+minHeap.peek())/2.0;
        }else if(maxHeap.size()>minHeap.size()){
            return maxHeap.peek()/1.0;
        }else{
            return minHeap.peek()/1.0;
        }
    }
}

Determine if the stack order is consistent with the stack order

Title Description:

Enter two integer sequences. The first sequence represents the stack's insertion order. Determine if the second sequence is likely to be the stack's pop-up order. Assume that all the numbers pushed into the stack are not equal. For example, sequence 1,2,3,4,5 is the stack's insertion order, and sequence 4,5,2,1 is the corresponding pop-up sequence for the stack sequence, but 4,3,5,1,2 is not the stack's pop-up sequence.(Note that the two sequences are of equal length)

Solving steps:

(1) Special judgment: When one of the lengths of the popA and pushA arrays is empty, there must be inconsistency

(2) First stack the first element in pushA.

(3) Set two pointers i and j to point to pushA and popA, respectively, to determine if the top element of stack stack is the same as popA[j] element, if the same, then go out of stack, J points to the next, if different, then loop through (3) until the same, if the index of i exceeds the step, then they will not be in the same order and return false;
Look directly at the code

import java.util.ArrayList;
import java.util.Stack;
public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        if(pushA.length==0 || popA.length==0){
            return false;
        }
        Stack<Integer> stack=new Stack<Integer>();
        int i=0;//Pointer to pushA
        int j=0;//Pointer to popA;
        stack.push(pushA[i++]);
        while(j<popA.length){
            while(stack.peek()!=popA[j]){
                //Continue stacking until popA[j] elements are the same
                if(i<pushA.length){
                    stack.push(pushA[i++]);
                }else{
                    return false;
                }
            }
            //i<pushA.length && peek()==pop[j]
            //Stack Out
            stack.pop();
            j++;
        }
        return true;
    }
}

The stack structure containing the Min function

Title Description:

Defines a stack structure with a function min to get the smallest element in the current stack, requiring an O(1) time complexity for the algorithm

Solving ideas:

This is a typical space-time idea. To define two stacks, one representing the ontology stack1 and the other stakc2 storing the minimum value in the current stack, you need to determine the size of the elements to be stacked and the top element of the stack2 stack, only value<=stack2.peek()If the top elements of stack2 and stack1 are the same, then the elements in stack2 must be updated at the same time.

Look directly at the code

import java.util.Stack;

class MinStack {

    /** initialize your data structure here. */
    private Stack<Integer> stack;
    private Stack<Integer> minStack;
    public MinStack() {
        stack=new Stack<>();
        minStack=new Stack<>();
        minStack.push(Integer.MAX_VALUE);
    }
    
    
    public void push(int val) {
        stack.push(val);
        minStack.push(Math.min(val,minStack.peek()));
    }
    
    public void pop() {
        stack.pop();
        minStack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

Chain list correlation

Delete duplicate list

Title Description:
In a sorted chain table, there are duplicate nodes, please delete duplicate nodes in the chain table, duplicate nodes are not retained, return the chain header pointer. For example, after processing 1->2->3->3->4->4->5, 1->2->5
Solving ideas:

(1) Create a new node Head pointing to the header node pHead

(2)tmp points to the actual head node pHead of the chain table

(3) If a prenode is needed to hold the previous node of the current node at the same time, pre=Head is initialized;So that subsequent nodes can be connected after deleting duplicate nodes
There are two cases to discuss:

When the header node has the same node, Head.next=tmp.next;

When the same node is not the header node, pre=pre.next;(pointing to the header node of the current list), tmp=tmp.next;

Graphical algorithm
[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-VU2KdeH4-1633614916565)(/img/delete duplicate list problem.png)]

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead){
        if(pHead==null || pHead.next==null){
            return pHead;
        }
        ListNode Head=new ListNode(0);
        Head.next=pHead;
        ListNode pre=Head;
        ListNode tmp=Head.next;
        while(tmp!=null){
            if(tmp.next!=null && tmp.val==tmp.next.val){
               while(tmp.next!=null && tmp.val==tmp.next.val){
                   tmp=tmp.next;
               }
               pre.next=tmp.next;
               tmp=tmp.next;
            }else{//Different Head Nodes
                pre=pre.next;
                tmp=tmp.next;
            }
        }
        return Head.next;
    }
}

Entry to find rings in a list of chains

Title Description:

Give a chain list, if it contains rings, find the entry node of the ring of the chain list, otherwise, output null.

Solving ideas:

(1) Use fast=fast.next.next;slow=slow.next;The fast pointer travels twice as long as the slow pointer. If there are rings, they will inevitably meet.

(2) After the first encounter, slow is restored to pHead, and fast still starts from the point of encounter. When both go forward again in the same speed reading, the next encounter is the starting point of the ring.

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead){
        if(pHead==null || pHead.next==null){
            return null;
        }
        ListNode slow=pHead;
        ListNode fast=pHead;
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(slow==fast){
                break;
            }
        }
        //The first time you meet, let slow go back to its starting point, and slow and fast go on at the same speed.
        //They meet again the starting point of the point ring
        slow=pHead;
        while(slow!=fast){
            fast=fast.next;
            slow=slow.next;
        }
        //Meet, slow is the starting point of the ring
        return slow;
    }
}

Joseph Ring Problem

Description of the problem:

First, let the children form a big circle. Then, he randomly assigned a number m to let the child with number 0 start counting. Each time the kid shouted m-1, he would sing a song in a column. Then he could pick any gift in the gift box and not return to the circle. From his next kid on, he would continue counting 0...m-1... so on until the last kid left.You can get a copy of the Bullock's famous "Detective Conan" collection without performing (limited quota!!). Please try to figure out which kid will get this gift? (Note: Kids are numbered from 0 to n-1)

Solving steps:

(1) To simulate the Joseph Ring problem using the list set in java, the key to simulate the Ring is: index%list.size();

(2) Initialize index as the previous location of the node to be deleted, and index+m is the current location of the node to be deleted. After deleting the completed node, you need to move index-to the previous location, so that the next cycle can continue deleting.

import java.util.*;
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        //Special Judgment
        if(n==0 || m==0){
            return -1;
        }
        LinkedList<Integer> list=new LinkedList<Integer>();
        //Create a circular chain table
        for(int i=0;i<n;i++){
            list.add(i);
        }
        //Represents the position of the index before the head node
        int index=-1;
        while(list.size()>1){
            index=(index+m)%(list.size());
            list.remove(index);
            index--;//Return the index to the position before the head node, the previous node
        }
        return list.get(0);
    }
}

Common Node in Two Chain Lists

Title Description:

Enter two linked lists to find their first common node. (Note that since the incoming data is a linked list, the tips for error test data are displayed in other ways to ensure that the incoming data is correct)

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-Z7U0QNdB-1633614916567)(./img/Double Chain List Public Node Title Description.png)]

Analysis of Solving Problems

(1) Use the double-pointer method to traverse two linked lists at the same time.

(2) If there is a common node, then the two pointers must intersect.

(3) However, the length of the two linked lists is not the same. In this case, one pointer must stop first (if no common node is found)At this point, the pointer will point to the head node of another list, but when the other pointer is finished, it will also point to the other list. So iterate over and over again, if there are nodes, they will point to the same node.

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
         if(pHead1==null && pHead2==null){
             return null;
         }
         if(pHead1==null || pHead2==null){
             return null;
         }
         ListNode p=pHead1;
         ListNode q=pHead2;
         while(p!=q){
             p=p.next;
             q=q.next;
             if(p!=q && p==null){
                 p=pHead2;
             }
             if(p!=q && q==null){
                 q=pHead1;
             }
         }
        return p;
    }
}

Copy complex chain list problems

Description of the problem:

Enter a complex list of chains (each node has a node value and two pointers, one pointing to the next node and another special pointer randomly pointing to a random node). Make a deep copy of the list and return the copied header node. (Note that do not return the node reference in the parameter in the output result, otherwise the decider will return to null directly.)

Solving ideas:

Since there is a Random pointer, you can consider using map to save the value of each node in the original chain table. Then, in turn, the duplicated nodes are taken out of the map in the order of the nodes in the chain table to build a new chain table. Use p and q pointers to point to the original chain table and the target chain table, respectively.
Code straight up is clearer and more appealing

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.*;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead){
        if(pHead==null){
            return null;
        }
        RandomListNode p = pHead;
        //New Node
        RandomListNode target = new RandomListNode(p.label);
        RandomListNode q=target;
        HashMap<RandomListNode,RandomListNode> map=new HashMap<RandomListNode,RandomListNode>();
        //Create a mapping relationship between two linked lists
        while(pHead!=null){
            map.put(pHead,new RandomListNode(pHead.label));
            pHead=pHead.next;
        }
        //Start copying
        while(q!=null){
            q.next=map.get(p.next);//Next node of p-point
            q.random=map.get(p.random);//random node of p
            
            p=p.next;
            q=q.next;
        }
        return target;
    }
}

Merge two linked lists

Title Description:

Enter two monotonically increasing chains and output the synthesized chains. Of course, we need the synthesized chains to satisfy the monotonic no-reduction rule.

Idea analysis:

(1) Set two pointers p and q to point to two linked lists, create a new target list to return as the final result, and create a new auxiliary pointer t:t=target for target

(2) Comparing the values of p and q nodes and discussing them in different cases, there are three cases:

  • P.val < q.val, then the next node of t is connected to p
  • p.val==q.val, t needs to be connected to p and q, respectively
  • P.val>q.val, then he needs to take q;
    (3) Finally, there may be two cases where the chains are not the same length, and two cases need to be considered, so that the long remaining chains are directly behind t.
    (4) Last note is to return target.next
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1==null && list2==null){
            return null;
        }
        if(list1==null){
            return list2;
        }
        if(list2==null){
            return list1;
        }
        ListNode p=list1;
        ListNode q=list2;
        ListNode target=new ListNode(-1);
        ListNode t=target;
        while(p!=null && q!=null){
            if(p.val<q.val){
                t.next=p;
                p=p.next;
                t=t.next;
            }else if(p.val==q.val){
                t.next=p;
                p=p.next;
                t=t.next;
                t.next=q;
                q=q.next;
                t=t.next;
            }else{
                t.next=q;
                q=q.next;
                t=t.next;
            }
        }
        //At least one list is completed first
        if(p==null){
            t.next=q;
            t=t.next;
        }else if(q==null){
            t.next=p;
            t=t.next;
        }else{
            return target.next;
        }
        return target.next;
    }
}

Inversion of Chain List

Title Description:

Given a chain list, find the reverse chain list of the chain list

Solving Ideas 1:

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-u1B3L5HS-1633614916568)(./img/chain list reverse operation step 1.png)]

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head==null){
            return null;
        }
       ListNode pre=null;
       ListNode cur=head;
       ListNode next=null;
       while(cur!=null){
           next=cur.next;
           //Join Reverse Chain List
           cur.next=pre;
           //Three pointers move backwards
           pre=cur;
           cur=next;
       }
        return pre;
    }
}

Solving Ideas 2:

This requires extra memory (each node needs to be copied)

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head==null){
            return null;
        }
        ListNode p=head;
        ListNode target=new ListNode(-1);
        ListNode t=target;
        while(p!=null){
            ListNode q=new ListNode(p.val);//Need to copy node
            q.next=t.next;
            t.next=q;
            // Stitching complete
            p=p.next;
            
        }
        return target.next;
    }
}

K th Last Node of Output Chain List

Title Description:

Enter a list of chains and output the last k th node in the list.

Solving ideas:

(1) Note the special case, when the length of the chain table is less than the input parameter K, it is invalid

(2) Set two pointers, p and q, let p walk k first, and then let p and Q walk simultaneously. When q is null, the node p points to is the last k node

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(count(head)<k){
            return null;
        }
        ListNode p=head;
        ListNode q=head;
        for(int i=0;i<k;i++){
            q=q.next;
        }
        while(q!=null){
            q=q.next;
            p=p.next;
        }
        return p;
    }
    private int count(ListNode head){
        if(head==null){
            return 0;
        }
        ListNode tmp=head;
        int count=0;
        while(tmp!=null){
            count++;
            tmp=tmp.next;
        }
        return count;
    }
}

Print chain list from end to end

Solving ideas:

(1) Reverse the list of chains before traversing it

(2) Store the list of chains using the stack first, then take out the data from the stack and print it;

Here's a code demonstration using scenario (2):

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.*;
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        if(listNode==null){
            return res;
        }
        Stack<Integer> stack=new Stack<Integer>();
        ListNode tmp=listNode;
        while(tmp!=null){
            stack.add(tmp.val);
            tmp=tmp.next;
        }
        while(!stack.isEmpty()){
            res.add(stack.pop());
        }
        return res;
    }
}

Merge K Ascending Chain Lists

  • Small Top Heap Use: The minimum number of elements is taken out of the small top heap each time;
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {

        if (lists.length == 0) {
            return null;
        }

        ListNode dummyHead = new ListNode(0);
        ListNode curr = dummyHead;
        PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val - o2.val;
            }
        });

        for (ListNode list : lists) {
            if (list == null) {
                continue;
            }
            pq.add(list);
        }

        while (!pq.isEmpty()) {
            ListNode nextNode = pq.poll();
            curr.next = nextNode;
            curr = curr.next;
            if (nextNode.next != null) {
                pq.add(nextNode.next);
            }
        }
        return dummyHead.next;
    }
}

Sort Chain List

class Solution {
    public ListNode sortList(ListNode head) {
        return mergeSort(head);
    }
    // Merge Sort
    private ListNode mergeSort(ListNode head){
        // Return without sorting if there is no node/only one node
        if (head==null||head.next==null) return head;
        // Fast or Slow Pointer Find Median
        ListNode slowp=head,fastp=head.next.next,l,r;
        while (fastp!=null&&fastp.next!=null){
            slowp=slowp.next;
            fastp=fastp.next.next;
        }
        // Merge and sort the right half
        r=mergeSort(slowp.next);
        // Flag for end of chain table judgement: End node.next==null
        slowp.next=null;
        // Merge and sort the left half
        l=mergeSort(head);
        return mergeList(l,r);
    }
    // Merge Chain List
    private ListNode mergeList(ListNode l,ListNode r){
        // Temporary Head Node
        ListNode tmpHead=new ListNode(-1);
        ListNode p=tmpHead;
        while (l!=null&&r!=null){
            if (l.val<r.val){
                p.next=l;
                l=l.next;
            }else {
                p.next=r;
                r=r.next;
            }
            p=p.next;
        }
        p.next=l==null?r:l;
        return tmpHead.next;
    }
}

tree

Non-recursive method of tree traversal in the first, middle and last order

Pre-order traversal

Solving ideas:

The order of preceding traversal is: root node, left subtree, right subtree, but when using non-recursive method, the stack structure is needed. In order to ensure the order mentioned above, the right node should be entered first, then the left node, so that the stack can be guaranteed left, then right!

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;
    }
}
*/
import java.util.*;
public class Solution{
    public void preOrder(TreeNode root){
        Stack<TreeNode> stack=new Stack<>();
        //Special Judgment
        if(root==null){
            return;
        }
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode head=stack.pop();
            //Operation to access the root node.
            if(head.right!=null){
                stack.push(head.right);
            }
            if(head.left!=null){
                stack.push(head.left);
            }
        }
    }
}

Intermediate traversal

Solving ideas:

Depending on the characteristics of intermediate traversal, for any node, the left node (if any), the right node (if any) are accessed first, so a stack structure is required:
The core idea is to start from the root node, stack all the left nodes, then go out of the stack one by one, and access the element, such as the current element and the right node, need to continue using the above logic, stack the left node of the current node to the end, and then go out of the stack and access it.

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution(){
    public void inorder(TreeNode root){
        Stack<TreeNode> stack=new Stack
        if(root==null){
            return ;
        }
        TreeNode tmp=root;
        while(tmp!=null || stack.isEmpty()){
            //The left node stays on the stack until it is empty
            while(tmp!=null){
                stack.push(tmp);
                tmp=tmp.left;
            }
            //This has reached the leaf node of the leftmost subtree
            if(!stack.isEmpty()){
                tmp=stack.pop();
                //Access the current node
                System.out.print(tmp.val);
                //tmp points to the right node, that is, the next round, the right node is on the stack;
                tmp=tmp.right;
            }
        }
    }
}

Post-order traversal

Solving ideas:
On the basis of ordered traversal, if the top element of the stack has no right subtree or if the right subtree has already been accessed, then the current node can be accessed. Otherwise, continue traversing the right subtree.

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution{
    public void postOrder(TreeNode root){
        Stack<TreeNode> stack=new Stack<>();
        TreeNode tmp=root;
        TreeNode lastVisited=root;//Viewed traversed nodes
        while(tmp!=null || stack.isEmpty()){
            //Traverse Left Node
            while(tmp!=null){
                stack.push(tmp);
                tmp=tmp.left;
            }
            //First look at the top element of the stack
            tmp=stack.peek();
            //If the tmp has no right node or if the right node has already been accessed, access the current tmp node
            if(tmp.right==null || lastVisited==tmp.right){
                //Access the current node
                System.out.println(tmp);
                //Set current node access
                lastVisited=tmp;
                tmp=null;
            }else{

                tmp=tmp.right;
            }
        }

    }
}


    //Double stack method
    public void posOrderUnRecur1(Node head){
         //Non-recursive, post-order traversal, double stack
        if(head == null) return;
        Stack<Ndoe> s1 = new Stack<>();
        Stack<Ndoe> s2 = new Stack<>();
        s1.push(head);
        //The root of a subtree goes first into s1, then out of stack into s2, while its left-right subtree goes first into S1
        //When left and right subtrees exit s1 and enter s2, they become right-down, left-up, and left-right-middle after S2
        while(!s1.isEmpty()){
            head = s1.pop();
            s2.push(head);
            if(head.left != null){
                s1.push(head.right);
            }
            if(head.right!=null){
                s1.push(head.right);
            }
        }
        //s2 out of stack access
        while(!s2.isEmpty()){
            System.out.print(s2.pop().val+" ");
        }
    }

Build Binary Tree and Traverse in Front, Middle and Post Order

import java.util.Scanner;
import java.util.Stack;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        //Build Binary Tree
        int count =sc.nextInt();
        int rootVal=sc.nextInt();
        TreeNode root=null;
        if(count==1){
            root=new TreeNode(rootVal);
            print(root);
            return;
        }
        root= createTree(sc);
        //Traversing Binary Trees (Front, Middle, Back)
        print(root);
    }
    
    //Define Tree Node
    private static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int val){
            this.val=val;
        }
    }
    //Build a binary tree from the input stream
    //Recursively Build Binary Tree
    private static TreeNode createTree(Scanner sc){
        int rootVal=sc.nextInt();
        int leftVal=sc.nextInt();
        int rightVal=sc.nextInt();
        TreeNode root=new TreeNode(rootVal);
        if(leftVal!=0){
            root.left=createTree(sc);
        }
        if(rightVal!=0){
            root.right=createTree(sc);
        }
        return root;
    }
    //Pre-order traversal (non-recursive)
    private static void preOrder(TreeNode root){
        if(root==null){
            return;
        }
        Stack<TreeNode> stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode head=stack.pop();
            System.out.print(head.val+" ");
            if(head.right!=null){
                stack.push(head.right);
            }
            if(head.left!=null){
                stack.push(head.left);
            }
        }
    }
    //Ordered traversal (non-recursive)
    private static void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        Stack<TreeNode> stack=new Stack<>();
        TreeNode tmp=root;//Auxiliary Pointer
        while(!stack.isEmpty() || tmp!=null){
            //Traversing Left Subtree
            while(tmp!=null){
                stack.push(tmp);
                tmp=tmp.left;
            }
            if(!stack.isEmpty()){
                //Determine if the top element of the stack has a right subtree
                tmp=stack.pop();
                //Traverse current node first
                System.out.print(tmp.val+" ");
                tmp=tmp.right;
            }
        }
    }
    //Post-order traversal (non-recursive)
    private static void postOrder(TreeNode root){
        if(root==null){
            return ;
        }
        TreeNode tmp=root;//Auxiliary pointer;
        TreeNode lastVisited=root;//Record node accessed
        Stack<TreeNode> stack=new Stack<>();
        while(!stack.isEmpty() || tmp!=null){
            while(tmp!=null){
                stack.push(tmp);
                tmp=tmp.left;
            }
            tmp=stack.peek();
            //When there is no right node or the right node has already been accessed, the current node can be accessed
            if(tmp.right==null || lastVisited==tmp.right){
                System.out.print(tmp.val+" ");
                stack.pop();
                lastVisited=tmp;//Settings have been accessed
                tmp=null;
            }else{
                tmp=tmp.right;//Otherwise, continue stacking
            }
             
        }
    }
    private static void print(TreeNode root){
        preOrder(root);
        System.out.println();
        inOrder(root);
        System.out.println();
        postOrder(root);
    }
     
}

Reconstruct Binary Tree (Medium Difficulty)

Title Description:
Rebuild a binary tree by entering the results of the prefix and median traversals of a binary tree. Assume that no duplicate numbers are included in the results of the prefix and median traversals entered. For example, rebuild the binary tree by entering the prefix traversal sequence {1,2,4,7,3,5,6,8} and the median traversal sequence {4,7,2,1,5,3,8,6}.

Analysis of solution ideas:
Pre-order traversal: from the root node, first access the root node, then the left subtree, then the right subtree; Medium-order traversal: first left subtree, then the root node, and finally the right subtree;

Algorithmic ideas:

(1) The first node in the pre array must be root, and the root must be again in the middle of the in. So if you find the location I of the root in the in, the in[0,i) is the left subtree of the root, the node tree of the left subtree is i, and the in[i+1,in.length] is the right subtree of the root.

(2) The left subtree in the preis: pre[1, i+1), length is i; the range of the right subtree is [i+1,pre.length]

(3) the left subtree in the in is: in [0, i]; the right subtree is: in [i+1, in.length]

(4) Recursive traversal until the pre and in arrays are empty.

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-K86qB2KB-1633614916573)(./img/rebuilt binary tree.png)]

code implementation

import java.util.Arrays;
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        //Special judgment, empty tree
        if(pre.length==0 || in.length==0){
            return null;
        }
        TreeNode root=new TreeNode(pre[0]);//Create a root node
        //Root node found in
        for(int i=0;i<in.length;i++){
            if(in[i]==pre[0]){
                    //Left subtree, notice that Arrys.copyOfRange is left closed and open
                root.left=reConstructBinaryTree(Arrays.copyOfRange(pre,1,1+i),Arrays.copyOfRange(in,0,i));
                root.right=reConstructBinaryTree(Arrays.copyOfRange(pre,1+i,pre.length),Arrays.copyOfRange(in,i+1,in.length));
                break;//The next time you recursively enter a for loop, you end the cycle after you find the left and right subtrees.
            }
            
        }
        return root;
    }
}

Mirror of Tree (Simple)

subject
Operates on a given binary tree and transforms it into a mirror of the source binary tree.

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-unZF33Iw-1633614916574)(./img/tree mirror case.png)]

Idea analysis:
Use the idea of recursion to clarify the end conditions of recursion and invoke your own conditions;

(1) End the current function directly when the root is empty

(2) Exchange of left and right nodes of the current root

(3) Start recursion with the same logic from the left subtree; start recursion with the same logic from the right subtree.

public class Solution {
    public void Mirror(TreeNode root) {
        if(root==null){
            return ;
        }
        //Swap left and right child nodes
         TreeNode tmp=root.left;
         root.left=root.right;
         root.right=tmp;
         //Recursive Left Subtree
        if(root.left!=null){
            Mirror(root.left);
        }
        //Recursive Right Subtree
        if(root.right!=null){
            Mirror(root.right);
        }   
    }
}

Finding the depth of a tree (simple)

principle
With recursion, when using recursion, the recursive condition is first derived, and then the recursive call is made.

import java.lang.Math.*;
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root==null){
            return 0;
        }
        //The left subtree and the right subtree use the same logic, do not go down one level, the result should be one, every recursion, for the root node of the tree
        return (Math.max(TreeDepth(root.left),TreeDepth(root.right))+1);
    }
}

Tree Balance Detection (Simple)

Title Description
Given a tree, determine if it is a balanced binary tree

Idea Analysis
Definition of balanced binary tree: The depth difference between left and right subtrees cannot exceed 1. When root is null, the tree must be a balanced binary tree. What we need to do is to detect all the left and right subtrees of the tree and determine if they conform to the definition of balanced binary tree.

Key to programming

(1)getDepth(), given the root node, find the depth of the node;

(2) To determine whether a tree conforms to the definition of a balanced binary tree;

(3) According to the same logic of judgment, recursively call to determine whether the left and right subtrees of this tree are balanced binary trees;

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        //Special Judgment
        if(root==null){
             return true;
         }
        //Determine if the current tree is a balanced binary tree
         if(Math.abs(getDepth(root.left)-getDepth(root.right))>1){
            return false;
        }
        //Recursively determine whether the left and right subtrees of the current node are balanced trees
        return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
    
    //Get the depth of a tree
    public int getDepth(TreeNode root){
        if(root==null){
            return 0;
        }
        return Math.max(getDepth(root.left),getDepth(root.right))+1;
    }
}

Hierarchical traversal of trees (medium)

Title Description
Hierarchical traversal, top-down, left-to-right binary tree traversal, each layer of nodes stored in a list, and finally all lists stored in the result set.

Idea Analysis
Two queues need to be used as buffers, the first queue to cache the nodes in the current layer and the second queue to cache the next node in the current layer. For each cycle, all elements in queue 1 should be guaranteed to be in queue 2, then the elements in queue 2 should be taken out and placed in the list in turn.

Used java library functions:

(1) Queues, which implement the java.util.Queue interface and the java.util.List interface, should be imported, so: Queue q=new LinkedList();

(2) Queue common methods: q.offer() queue, q.poll() queue, q.peek() view the first element of the queue, but not out of the queue.

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        //Used to store the final result set
        ArrayList<ArrayList<Integer>> listOuter=new ArrayList<ArrayList<Integer>>();
        //Queue 1 caches the values for each layer
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        //Queue 2 caches the value of the next layer in the current layer
        Queue<TreeNode> queue2=new LinkedList<TreeNode>(); 
        if(pRoot==null){
            return listOuter;
        }
        //1. Root Node First Entry Queue 1
        queue.offer(pRoot);
        while(!queue.isEmpty()){
            //Remove all root nodes from queue 1 at once and place them in queue 2
            while(!queue.isEmpty()){
                TreeNode curNode=queue.poll();
                queue2.offer(curNode);
            }
            ArrayList<Integer> listInner=new ArrayList<Integer>();
            //The left and right nodes of the current layer are the root nodes of the next layer
            //
            while(!queue2.isEmpty()){
                TreeNode curNode2=queue2.poll();
                listInner.add(curNode2.val);//Cache the value of the current layer
                if(curNode2.left!=null){
                    queue.offer(curNode2.left);//Stores the root node of the next layer
                }
                if(curNode2.right!=null){
                    queue.offer(curNode2.right);//Stores the root node of the next layer
                }
            }
            listOuter.add(listInner);
        }
        return listOuter;
    }
}

//Just use a queue
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        if(root==null){
            return res;
        }
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                TreeNode curNode=queue.poll();
                if(curNode.left!=null){
                    queue.add(curNode.left);
                }
                if(curNode.right!=null){
                    queue.add(curNode.right);
                }
                res.add(curNode.val);
            }
        }
        return res;
        
    }
}

Next Node of Binary Tree (Medium)

Title Description
Given a binary tree and one of its nodes, find the next node in the middle traversal order and return. Note that the nodes in the tree contain not only left and right child nodes, but also pointers to the parent node.

Analysis
The input node is determined by whether it contains a right subtree or not.

(1) If the input parameter contains a right subtree, find the leftmost leaf node of the right subtree

(2) If the input parameter does not have a right subtree, look up its ancestor node until the following condition is met: the current node must be the left child of the ancestor.

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode){
        //Special Judgment
        if(pNode==null){
            return null;
        }
        //If a right subtree exists, the leftmost node of the right subtree is found.
        if(pNode.right!=null){
            //Find the deepest left node of the right subtree
            TreeLinkNode node=pNode.right;
            while(node.left!=null){
                node=node.left;
            }
            return node;
        }
        //If the right subtree is empty, it loops up to find its ancestor node.
        //Until an ancestor node is found, the current node is the left child of the ancestor node
        while(pNode.next!=null){
            if(pNode.next.left==pNode){
                return pNode.next;
            }
            pNode=pNode.next;
        }
        return null;
    }
    
}

Converting a Binary Sort Tree to a Double-Ended Chain List (Medium)

Title Description
Enter a binary search tree and convert the binary search tree into a sorted two-way Chain table. This requires that no new nodes can be created, only the pointer of the nodes in the tree can be adjusted.

For example, a binary tree is:

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-bp0uznBM-1633614916576)(./img/BST chain table.png)]

It can be converted to:

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-mlvUZukP-1633614916577)(./img/BST chain table 2.png)]

Idea analysis:

Look at the following picture before explaining:

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-vHTntPud-1633614916578)(./img/BST chain table 3.png)]

The problem with binary trees can basically be summarized as the problem of recursive calls, and the key to recursive calls is to let the function handle the current node well.The rest is done recursively. This problem can be broken down as follows: Sort binary tree is considered as three components: root node 4, left subtree with 2 root nodes and right subtree with 6 root nodes. Based on the idea of recursion, we process the root node first, while the other two subtrees are called recursively with the same logic. Sort binary tree one at the same timeThere is a relationship between ordered and ordered traversal, so we should complete the process of binary tree transformation during ordered traversal. Another key point of the transformation process is to make the right pointer of the last node lastNode of the left subtree point to the current node, the left pointer of the current node point to lastNode, and when root node 4 finishes the transformation, LastNode is updated, that is LastNode=Node;Since this lastNode relies on a left subtree, it should complete the left subtree recursively, then the right subtree recursively (the overall framework is: middle-order traversal)

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode lastNode=null;
    public TreeNode Convert(TreeNode pRootOfTree){
        if(pRootOfTree==null){
            return null;
        }
        inorder(pRootOfTree);
        //Getting the Head Node of a Double-Ended Chain List
        while(lastNode.left!=null){
            lastNode=lastNode.left;
        }
        return lastNode;
    }
    
    private void inorder(TreeNode node){
        if(node==null){
            return;
        }
        inorder(node.left);
        //Initialize, lastNode is the current node, otherwise null pointer exception will be reported
        if(lastNode==null){
            lastNode=node;
        }else{
            node.left=lastNode;
            lastNode.right=node;
            lastNode=node;
        }
        inorder(node.right);
    } 
}

Versions that need to process input and output

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
    static TreeNode lastNode = null;
    static TreeNode firstNode=null;
    public static void main(String[] args) throws IOException{ 
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String[] strs=br.readLine().trim().split(" ");
        int nodeCount=Integer.parseInt(strs[0]);
        int[][] arr = new int[nodeCount+1][2];//Record left and right child nodes of each node
        //Create follower nodes and enter them in arr
        String[] nodes=br.readLine().trim().split(" ");
        int rootVal=Integer.parseInt(nodes[0]);
        int leftVal=Integer.parseInt(nodes[1]);
        int rightVal=Integer.parseInt(nodes[2]);
        arr[rootVal][0]=leftVal;
        arr[rootVal][1]=rightVal;
        for(int i=1;i<nodeCount;i++){
            nodes=br.readLine().trim().split(" ");
            arr[Integer.parseInt(nodes[0])][0]=Integer.parseInt(nodes[1]);
            arr[Integer.parseInt(nodes[0])][1]=Integer.parseInt(nodes[2]);
        }
        TreeNode root=new TreeNode(rootVal);
        createTree(root,arr);
        inOrderHelper(root);
        while(firstNode!=null){
            System.out.print(firstNode.val+" ");
            firstNode=firstNode.right;
        }
    }

    private static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int val) {
            this.val = val;
        }
    }

    // Building a lesson binary tree from input streams
    private static void createTree(TreeNode root,int[][] arr) {
        if(root==null){
            return ;
        }
        int leftVal=arr[root.val][0];
        int rightVal=arr[root.val][1];
        if (leftVal != 0) {
            TreeNode leftNode=new TreeNode(leftVal);
            root.left=leftNode;
            createTree(leftNode,arr);
        }
        if (rightVal != 0) {
            TreeNode rightNode=new TreeNode(rightVal);
            root.right=rightNode;
            createTree(rightNode,arr);
        }
    }

    private static void inOrderHelper(TreeNode root) {
        if (root == null) {
            return;
        }
        inOrderHelper(root.left);
        // Steps to build a double-ended chain table
        if (lastNode == null) {
            lastNode = root;
            firstNode=root;
        } else {
            root.left = lastNode;
            lastNode.right = root;
            lastNode = root;
        }
        inOrderHelper(root.right);
    }
}

Binary Tree Expanded into Chain List

class Solution {
    public void flatten(TreeNode root) {
        while(root!=null){
            if(root.left==null){
                root=root.right;
            }else{
                //1 Find the rightmost node of the left subtree first
                TreeNode tmp=root.left;
                while(tmp.right!=null){
                    tmp=tmp.right;
                }
                //2. Connect the right subtree of the current node to the rightmost node of the current node's left subtree;
                tmp.right=root.right;
                //3. Connect the left subtree of root to the right node of root
                root.right=root.left;
                root.left=null;
                //Do a similar operation on the next right node
                root=root.right;
            }    
        }

    }
}

Subtree problem (simple)

Description of the problem:
Enter two binary trees A and B to determine if B is a substructure of A.

How to handle the tree problem:
Ultimately, most of the binary tree problems can be solved recursively. The tree can be divided into three parts: the current tree formed by the root node, the left subtree of the root node, and the right subtree of the root node. The core logic of our recursion is: only the current node! Only the current node! Only the current node! Only the current node, because the logic of other nodes is the same.So you can use recursive calls to pass in root.left and root.right, respectively;

Problem Analysis:
To judge whether Tree B is a substructure of Tree A according to the above way of thinking, two major problems need to be solved:

(1) How to judge that two trees are identical

  • Special judgment: B null is true; B!=null && Anull must be false;
  • Using recursive judgment, all nodes of the two trees are equal (first the current node, then the left node, and finally the right node)

(2) The tree A is divided into three parts: tree A, left subtree and right subtree; next, as long as one of the three conditions is satisfied, tree B can be determined as a subtree of tree A.

  • Tree B is the same as Tree A
  • The left subtree of tree B and A is the same (recursive)
  • The right subtree of tree B and A is the same (recursive)
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    //Determining whether root2 is a subtree of root1
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        //Special Judgment
        if(root1==null || root2==null){
            return false;
        }
        return isSame(root1,root2) || HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);
    }
    //Judging whether two trees are the same
    private boolean isSame(TreeNode root1,TreeNode root2){
        //Special judgment, if the B-tree is empty, both return true
        if(root2==null){
            return true;
        }
        //B!==Null & & A==null, then B ratio cannot be a subtree of A, returning false
        if(root1==null){
            return false;
        }
        boolean res=true;
        res=res && (root1.val==root2.val) && isSame(root1.left,root2.left) && isSame(root1.right,root2.right);
        return res;
    }
}

The k th node of a binary search tree

Title Description
Given a binary search tree, find the k th smallest node in it. For example, (5, 3, 7, 2, 4, 6, 8) the value of the third smallest node in the order of node size is 4.

Idea analysis:
The BST problem alone is bound to have a great connection with the middle traversal, because the middle traversal of BST happens to be the sequence of nodes from small to large. The idea is simple: add the middle traversal sequence of this lesson tree to the queue (this process is completed during the middle traversal), and then read to the K first node.

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    TreeNode KthNode(TreeNode pRoot, int k){
        if(k<1){
            return null;
        }
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        inorder(pRoot,queue);
        if(queue.size()<k){
            return null;
        }
        
        while(k>1){
            queue.poll();
            k--;
        }
        return queue.poll();
    }
    //Traverse the root tree in middle order and queue in turn
    private void inorder(TreeNode root,Queue queue){
        if(root==null){
            return;
        }
        inorder(root.left,queue);
        //Queue the current node
        queue.offer(root);
        inorder(root.right,queue);
    }

}

Serialization and Deserialization of Binary Trees

Title Description:
Please implement two functions to serialize and deserialize the binary tree, respectively
[Note]Serialization of a binary tree means that the result of a binary tree traversed in a certain format is saved as a string so that the binary tree built in memory can be persisted. Serialization can be modified based on the binary tree traversal in order of order, order, order, and order. The serialization result is a string which is serialized throughA symbol denotes an empty node (#) with!! denoting the end of a node value (value!). Deserialization of a binary tree refers to the reconstruction of a binary tree based on the result str of a serialized string obtained in some traversal order.

Title Analysis:
You can use 4 traversal methods, such as front, middle, back, and hierarchy, to achieve this. Note that they use the same traversal method during serialization and deserialization, while following the same conventions

The java toolkit used:
StringBuilder, common methods in strings;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    private int index=-1;
    String Serialize(TreeNode root) {
        StringBuilder sb=new StringBuilder();
        serializeHelper(root,sb);
        return sb.toString();
    }
    //Serialization using prefix traversal
    private void serializeHelper(TreeNode root,StringBuilder sb){
        //Special Judgment
        if(root==null){
            sb.append("#!");
            return;
        }
        sb.append(root.val).append("!");
        serializeHelper(root.left,sb);
        serializeHelper(root.right,sb);
    }
    TreeNode Deserialize(String str) {
       String[] strs=str.split("!");
       return deserializeHelper(strs);
    }
    private TreeNode deserializeHelper(String[] strs){
        index++;
        //The first node cannot be empty
        if(!strs[index].equals("#")){
            TreeNode curNode=new TreeNode(Integer.parseInt(strs[index]));
            curNode.left=deserializeHelper(strs);
            curNode.right=deserializeHelper(strs);
            return curNode;
        }
        return null;
    }
}

Z-shaped Print Tree

Description of the title:
Please implement a function to print binary trees in zigzag, that is, the first line is printed left-to-right, the second layer is printed right-to-left, the third line is printed left-to-right, and so on.

Idea analysis:
The idea of this question is to traverse through the layers in order, and through observation we find that when even layers are added to the list in order,When odd layers are added to the list in reverse order, the level variable can be introducedTo record the current layer. The idea for hierarchical traversal is simple: use a queue buffer, when initialized, put the root node in the queue, calculate the size of the current queue, and take out size nodes from the queue each time. These nodes are the nodes of the current layer. If you need to print in reverse order, there are two ways:

  • list.add(0,node);Add from 0 index at a time;
  • Take advantage of the stack's characteristics, putting it on the stack first, then going out
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> results=new ArrayList<ArrayList<Integer>>();
         //Special Judgment
        if(pRoot==null){
            return results;
        }
        Queue<TreeNode> queue=new LinkedList<TreeNode>();
        int level=0;
        queue.offer(pRoot);
        while(!queue.isEmpty()){
            int size=queue.size();
            ArrayList<Integer> list=new ArrayList<Integer>();
            Stack<TreeNode> stack=new Stack<TreeNode>();
            for(int i=0;i<size;i++){
                TreeNode curNode=queue.poll();
                if(level%2==0){
                    //Even layers, add sequentially
                    list.add(curNode.val);
                }else{//Put in reverse order in list
                    list.add(0,curNode.val);
                    //stack.add(curNode);
                }
                if(curNode.left!=null){
                    queue.offer(curNode.left);
                }
                if(curNode.right!=null){
                    queue.offer(curNode.right);
                }
            }
            //while(!stack.isEmpty()){
                //list.add(stack.pop().val);
            //}
            level++;
            results.add(list);
        }
        return results;
    }
}

Symmetric Binary Tree

Title Description:
Determines whether a tree is a symmetric binary tree with left and right nodes symmetrical around the central axis
Solving ideas:
The first function is how to judge whether two trees are symmetrical. It is recursive that if both root nodes are empty, they must be symmetrical. If only one is empty, they must be asymmetrical. If neither is empty, they need to be equal.Then use the same logical framework to recursively judge the left and right subtrees, that is, the right node of the left subtree should be equal to the left node of the right subtree, and the left node of the right subtree should be equal to the right node of the left subtree; the recursive problem is the problem responsible for the current node; how to judge whether two trees are symmetrical or not, then the symmetry of a tree is not the left subtree and the right subtree of this treeOf course, there must be a special judgment: empty trees must be symmetrical, only one subtree must be asymmetrical, and other cases can be judged by the above functions.

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot){
        if(pRoot==null){
            return true;
        }
        if(pRoot.left==null && pRoot.right==null){
            return true;
        }
        if(pRoot.left==null || pRoot.right==null){
            return false;
        }
        return sysmmetrical(pRoot.left,pRoot.right);
    }
    //Determine if two trees are symmetrical
    private boolean sysmmetrical(TreeNode root1,TreeNode root2){
        //Two empty trees are symmetrical
        if(root1==null && root2==null){
            return true;
        }
        //Only one empty must be asymmetric
        if(root1==null || root2==null){
            return false;
        }
        //If the two root nodes are not empty, the values of the two nodes are required to be equal.
        return root1.val==root2.val && sysmmetrical(root1.left,root2.right) && sysmmetrical(root1.right,root2.left);
    }
}

Summary of Root Node to Leaf Node and sum Issues

Is there a path

Title Description:
Given a binary tree and a target, it is determined whether there is a path from the root node to the leaf node in the tree. The sum of all the node values on this path equals the target and the leaf node.
Idea analysis:
Use recursive method to solve, if the value of the current node is a leaf node and its value is the target value, end recursion, find; otherwise, in determining whether the value of the left subtree to the leaf node is sum-target, the same is true for the right subtree, the relationship is ||

public boolean hasPathSum(TreeNode root, int sum) {
    if (root == null)
        return false;
    int val = root.val;
    if (root.left == null && root.right == null && val == sum)
        return true;
    return hasPathSum(root.left, sum - val) || hasPathSum(root.right, sum - val);
}

Find all paths

Title Description:
Enter the root node and an integer of a binary tree, and print out the sum of the values of the nodes in the binary tree in dictionary order as all paths of the input integer. The path is defined as a path formed from the root node of the tree down to the node that passes through the leaf node.

Title Analysis:
The core idea of this question is the same as that of the previous one, except that a list is needed to store the currently found path. Because parameters in java are value-passing, you need to copy the previous list each time you enter a recursive call.

    /**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.ArrayList;
public class Solution {
    
    
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        //Record total path
        ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
        //Record each path
        ArrayList<Integer> list=new ArrayList<Integer>();
        findPath(root,target,list,res);
        return res;
    }
    private void findPath(TreeNode root,int target,ArrayList<Integer> list, ArrayList<ArrayList<Integer>> res){
        if(root==null){
            return;
        }
        if(root.left==null && root.right==null && root.val==target){
            list.add(root.val);
            res.add(list);
            return;
        }
        //To join the value of the root node, continue to recurse down
        list.add(root.val);
        if(root.left!=null){
            //This is based on the previous list, so copy
            ArrayList<Integer> leftList=new ArrayList<Integer>(list);
            findPath(root.left,target-root.val,leftList,res);
        }
        if(root.right!=null){
            //copy
             ArrayList<Integer> rightList=new ArrayList<Integer>(list);
            findPath(root.right,target-root.val,rightList,res); 
        }
    }
}

A list replication method used: new ArrayList(list);Copy list;

Calculate the total number of paths

Title Description:

Enter the root node of a binary tree and an integer, and print out in dictionary order the sum of the node values in the binary tree as the total number of paths for the input integer.
Idea analysis:

Just like the previous title, look directly at the code

class Solution {
    public int pathSum(TreeNode root, int sum) {
        //Special Judgment
        if(root==null){
            return 0;
        }
        //From the root path, iterate through each node recursively
        int rootSum=findPathFromNode(root,sum);
        int leftSum=pathSum(root.left,sum);
        int rightSum=pathSum(root.right,sum);
        return rootSum+leftSum+rightSum;
    }

    //Find a path down from Node, which satisfies the path and=sum
    private int findPathFromNode(TreeNode node,int sum){
        if(node==null){
            return 0;
        }
        //Current node value==sum, path is 1
        int pathSum=node.val==sum?1:0;
        //Recursively find left subtree if path can be found
        int leftSum=findPathFromNode(node.left,sum-node.val);
        //Recursively to the right to find out if a path can be found
        int rightSum=findPathFromNode(node.right,sum-node.val);
        return leftSum+rightSum+pathSum;
    }
}

BST Postorder Traversal Sequence

Title Description:
Enter an integer array to determine if it is the result of a binary search tree's postorder traversal. If it is, output Yes, otherwise output No. Assume that any two numbers of the input array are different from each other.

Idea analysis:
The sequential sequence of BST has the following characteristics: the last element is the root node, the left half (left subtree) of the remaining elements is smaller than the root node, and the right half (right subtree) of the remaining elements is larger than the root node.The key point is to find the dividing point between left and right subtrees; two fo loops can solve it; for left and right subtrees, recursive solution is also used, in which the end condition of recursion should be noted: start>=root, why? When start==root, only the root node must be true, and when start>root, only the left subtree;

public class Solution {
    int index=0;
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence==null || sequence.length==0){
            return false;
        }
        return verifyHelper(sequence,0,sequence.length-1);
    }
    private boolean verifyHelper(int[] sequence,int start,int root){
        //Root node only
        if(start>=root){
            return true;
        }
        int key=sequence[root];//The last value of the array must be the value of the root node
        //Find the dividing point of left and right subtrees
        //The left side of i is all less than the key, and the right side of i is all greater than the key
        int i=0;
        for(i=start;i<root;i++){//[0,root)
            if(sequence[i]>key){
                break;
            }
        }
        for(int j=i;j<root;j++){
            if(sequence[j]<key){
                return false;
            }
        }
        //I found;The left subtree is [0,i-1], and the right subtree is [i,root-1]
        //Use a recursive approach
        return verifyHelper(sequence,start,i-1) && verifyHelper(sequence,i,root-1);
        
    }
}

Print the boundary nodes of a binary tree

Title Description:

Print the boundary point counterclockwise, as defined by the boundary node.
Standard One:

1, the root node is the boundary node.

2, leaf nodes are boundary nodes.

3. If a node is the leftmost or rightmost in its layer, it is also a boundary node.

Standard 2:

1, the root node is the boundary node.

2, leaf nodes are boundary nodes.

3. The path that extends down the left boundary of the tree is the boundary node.

4. The path that extends down the right boundary of the tree is the boundary node.

[External chain picture transfer failed, source station may have anti-theft chain mechanism, it is recommended to save the picture and upload it directly (img-nRMsTR2Y-1633614916582)(./img/Print Binary Tree Boundary Node.png)]

Solving ideas:

Standard 1: Set up a levelLR to store the leftmost and rightmost nodes of each layer, populate the levelLR during the preceding traversal, and implement a method to print leaf nodes that are not in the levelLR. The step of printing the boundary nodes counterclockwise in turn can be understood as: traversing the left node of levlelLR (levelLR[i][0]) from top to bottom;Print the leaf node at the top of each layer, and it can no longer be in the levelLR (because it has to be weighted);From bottom to top, the right node of levelLR (levelLR[j][1]) is traversed, and the left node is also traversed to de-weight.

Standard 2: Counterclockwise printing can be abstracted as: root - left subtree - bottom leaf node; bottom leaf node - right subtree, root node; when printing left subtree, only leaf node is considered, or (the node is a left child and he has no right brothers);When printing the right subtree, consider the leaf node or (the node is a right child and has no left brothers) in a post-order traversal fashion; the overall steps are: left first, then right, or, when there is only left and only right, beat aside;

import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String[] strs=br.readLine().trim().split(" ");
        int count =Integer.parseInt( strs[0]);
        int rootVal=Integer.parseInt(strs[1]);
        int[][] arr=new int[count+1][2];
        for(int i=0;i<count;i++){
            String[] nodes=br.readLine().trim().split(" ");
            arr[Integer.parseInt(nodes[0])][0]=Integer.parseInt(nodes[1]);
            arr[Integer.parseInt(nodes[0])][1]=Integer.parseInt(nodes[2]);
        }
        //Create Root Node
        TreeNode root=new TreeNode(rootVal);
        createTree(root,arr);
        int height=getHeight(root);
        TreeNode[][] levelLR=new TreeNode[height][2];
        setLevelLR(root,levelLR,0);
        printEdge1(root,levelLR);
        System.out.println();
        printEdge2(root);
    }
    
    private static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int val){
            this.val=val;
        }
    }
    private static void createTree(TreeNode root,int[][] arr){
        if(root==null){
            return;
        }
        int i=root.val;
        int leftVal=arr[i][0];
        int rightVal=arr[i][1];
        if(leftVal!=0){
            TreeNode left=new TreeNode(leftVal);
            root.left=left;
            createTree(root.left,arr);
        }
        if(rightVal!=0){
            TreeNode right=new TreeNode(rightVal);
            root.right=right;
            createTree(root.right,arr);
        }
    }
    private static int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }
        return 1+Math.max(getHeight(root.left),getHeight(root.right));
    } 
    /** levelLR[levelCount][2]Is an array of left and right nodes stored in each layer.
    *levelLR[i][0]:The leftmost node in layer i and the rightmost node in layer i.
    **/
    private static void setLevelLR(TreeNode root,TreeNode[][] levelLR,int level){
        if(root==null){
            return;
        }
        levelLR[level][0]=levelLR[level][0]==null?root:levelLR[level][0];//Leftmost Node
        levelLR[level][1]=root;//The rightmost node;
        //Recurse to the next level, left to right
        setLevelLR(root.left,levelLR,level+1);
        setLevelLR(root.right,levelLR,level+1);
    }
    //Print the leaf node, but the leaf node cannot be in the levelLR because the node in the levelLR has already been printed
    private static void  printLeafNotInLevelLR(TreeNode root,TreeNode[][] levelLR,int level){
        if(root==null){
            return ;
        }
        //Leaf nodes not in levelLR
        if(root.left==null && root.right==null && root!=levelLR[level][0] && root!=levelLR[level][1]){
            System.out.print(root.val+" ");
        }
        //Recursive so leaf nodes (counterclockwise, left to right)
        printLeafNotInLevelLR(root.left,levelLR,level+1);
        printLeafNotInLevelLR(root.right,levelLR,level+1);
    }
    //Print Boundary Nodes
    private static void printEdge1(TreeNode root,TreeNode[][] levelLR){
        if(root==null){
            return;
        }
        //Print the leftmost boundary first
        for(int i=0;i<levelLR.length;i++){
            System.out.print(levelLR[i][0].val+" ");
        }
        //Lowest leaf node (except left and right boundaries)
        printLeafNotInLevelLR(root,levelLR,0);
        
        //Print the rightmost boundary
        for(int i=levelLR.length-1;i>=0;i--){
            if(levelLR[i][0]!=levelLR[i][1]){
                 System.out.print(levelLR[i][1].val+" ");
            }
           
        }
    }
    //********************************************Printing Standard 2*******************************/
    private static void printEdge2(TreeNode root){
        if(root==null){
            return;
        }
        //Print the root node first
        System.out.print(root.val+" ");
        if(root.left!=null && root.right!=null){
             //Print on the left boundary and its extension
            printLeft(root.left,true);
            //Print right boundary and its extension
            printRight(root.right,true);
        }else{
            //If you have a left child, recurse left, otherwise recurse right
            printEdge2(root.left!=null?root.left:root.right);
        }
       
        
    }
    //Print left, first root, left, right
    private static void printLeft(TreeNode root,boolean print){
        if(root==null){
            return ;
        }
        if(print || (root.left==null && root.right==null)){
            //Only leaf nodes or print s are true
            System.out.print(root.val+" ");
        }
        printLeft(root.left,print);
        //The position of the right node at the current node, only if the left node is empty, consider printing the right node (the node must also be a leaf node);
        printLeft(root.right,print && root.left==null?true:false);
        
    }
    //Print right boundary, left, right, root;
    private static void printRight(TreeNode root,boolean print){
        if(root==null){
            return;
        }
        //When the current node is on the left node, consider printing the node only if the right node is empty (and the node must also be a leaf node)
        printRight(root.left,print && root.right==null?true:false);
        printRight(root.right,print);
        //Print Root Node
        if(print || (root.left==null && root.right==null)){
            System.out.print(root.val+" ");
        }
    } 
}

Merge Binary Tree

  • Problem Description
    Given two binary trees, imagine that when you cover one of them over the other, some nodes of the two binary trees overlap.
    You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, their values are added as the new value of the merged node, otherwise nodes that are not NULL will act directly as nodes of the new binary tree.
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
       if(root1==null){
           return root2;
       }
       if(root2==null){
           return root1;
       }
       //By doing so, it must be that both root1 and root2 are not null;
       root1.left=mergeTrees(root1.left,root2.left);
       root1.right=mergeTrees(root1.right,root2.right);
       return root1;
    }
}

Diameter of Binary Tree

Problem Description

Given a binary tree, you need to calculate its diameter length. The diameter length of a binary tree is the maximum of the path lengths of any two nodes. The path may or may not pass through the root node.

class Solution {
    /**
    Idea: Maximum sum of left and right depths
     */
    private int result=0;//Record results
    public int diameterOfBinaryTree(TreeNode root) {
        if(root==null){
            return 0;
        }
        getDeth(root);
        return result;
    }

    /**
        Get the depth of the tree
     */
    public int getDeth(TreeNode root){
        if(root==null){
            return 0;
        }
        int left=root.left==null?0:getDeth(root.left)+1;
        int right=root.right==null?0:getDeth(root.right)+1;
        result=Math.max(result,left+right);
        return Math.max(left,right);//Maximum Depth
    }

Flip Binary Tree

Problem Description

Given a binary tree, you need to calculate its diameter length. The diameter length of a binary tree is the maximum of the path lengths of any two nodes. The path may or may not pass through the root node.

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root==null){
            return null;
        }
        //Swap left and right child nodes
        TreeNode tmp=root.left;
        root.left=root.right;
        root.right=tmp;
        //Do the same for left and right subtrees
        root.left=invertTree(root.left);
        root.right=invertTree(root.right);
        return root;
    }
}

Common Node of Binary Tree

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return null;
        }        
        // Root node is the common ancestor of all nodes
        if(root==p || root==q){
            return root;
        }
        TreeNode leftRoot=lowestCommonAncestor(root.left,p,q);
        TreeNode rightRoot=lowestCommonAncestor(root.right,p,q);
        //Ancestor nodes can only be in three cases: root node, root node of left subtree, root node of right subtree;
        if(leftRoot!=null && rightRoot!=null){
            return root;
        }
        if(leftRoot!=null){
            return leftRoot;
        }
        if(rightRoot!=null){
            return rightRoot;
        }
        return null;
    }
}

Verify that a binary tree is a valid binary search tree

class Solution {
    long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if (root == null) {
            return true;
        }
        // Access left subtree
        if (!isValidBST(root.left)) {
            return false;
        }
        // Access the current node: If the current node is less than or equal to the previous node of the intermediate traversal, then BST is not satisfied, false is returned; otherwise, traversal continues.
        if (root.val <= pre) {
            return false;
        }
        pre = root.val;
        // Access right subtree
        return isValidBST(root.right);
    }  
}

dynamic programming

Dynamic Programming Problem Set

(1) Determining the state (an independent variable in the problem description) and selecting (actions that may change the state)

(2) Define dp tables

(3) Consider the logical relationship of state transition based on choice

Cord shearing problem

Problem Description
With a rope of length m, cut the rope into n segments of integer length, n<=m, and find the maximum product of each length.

Solving problems

Solve using a dynamic programming approach, starting with a dynamic programming routine:

Status: Length of rope

Defines dp:dp[i] to represent the maximum product of a segment of a rope whose length is i;

Choose: Cut and do not cut, or dp[i], deduce from the bottom up: j*dp[i-j] means that after cutting, the first length is j, then the maximum product of the remaining length is dp[i-j], that is, there are many cases when cutting based on the first length, we need to list them all;

base_case: Obviously, when i<=4, dp[i]=i;

import java.util.*;
public class Solution {
    public int cutRope(int target) {
        //Special judgment, 1=1*1
        if(target==2){
            return 1;
        }
        if(target==3){
            return 2;
        }
        int[] dp=new int[target+1];
        
        //base_case
        for(int i=1;i<=4;i++){
            dp[i]=i;
        }
        //dp[5]=max(dp[5],j*dp[i-j])--->dp[6]---->dp[target]
        for(int i=5;i<=target;i++){
            //j is the length of the first piece of rope after cutting
            for(int j=1;j<i;j++){
                //There are two options:
                //Do not clip dp[i]
                //Cut - how to cut, listed in order of length of the first paragraph, j*dp[i-j]
                dp[i]=Math.max(dp[i],j*dp[i-j]);
            }
        }
        return dp[target];
    }
}

Convert Binary Tree to Accumulated Number

class Solution {
   int num = 0;
    public TreeNode convertBST(TreeNode root) {
        if (root != null) {
            //Traversing right subtree
            convertBST(root.right);
            //Traversal vertices
            root.val = root.val + num;
            num = root.val;
            //Traversing Left Subtree
            convertBST(root.left);
            return root;
        }
        return null;
    }
}

Backtrace algorithm

Sum of combinations

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(candidates);
        backtrack(candidates, target, res, 0, new ArrayList<Integer>());
        return res;
    }
    private void backtrack(int[] candidates, int target, List<List<Integer>> res, int i, ArrayList<Integer> tmp_list) {
        if (target < 0) return;
        if (target == 0) {
            res.add(new ArrayList<>(tmp_list));
            return;
        }
        for (int start = i; start < candidates.length; start++) {
            if (target < 0) break;
            tmp_list.add(candidates[start]);
            backtrack(candidates, target - candidates[start], res, start, tmp_list);
            tmp_list.remove(tmp_list.size() - 1);
        }
    }
}

Full Arrangement

class Solution {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> list = new ArrayList<>();
        backtrack(res, list, nums);
        return res;        
    }
    
    public void backtrack(List<List<Integer>> res, List<Integer> list, int[] nums) {
        if(list.size() == nums.length) {
            res.add(new ArrayList<Integer>(list));
            return;
        }
        for(int num : nums) {
            if(!list.contains(num)) {
                list.add(num);
                backtrack(res, list, nums);
                list.remove(list.size() - 1);
            }
        }
    }
}

Tags: Java

Posted on Thu, 07 Oct 2021 13:16:36 -0400 by AshtrayWaterloo