# 1. Prefix Tree

A Trie tree, also known as a dictionary tree, a Prefix Tree, a word lookup tree, or a key tree, is a multifork tree structure. Typical applications are for counting and sorting large numbers of strings (but not just strings)It has the advantage of minimizing unnecessary string comparisons and being more efficient than hash tables.

The core idea of Trie is space for time. Use the common prefix of the string to reduce the cost of query time in order to improve efficiency.

Trie trees also have their drawbacks, which are very memory intensive.

The basic structure is as follows:

[External chain picture transfer failed, the source may have anti-theft chain mechanism, suggest saving and uploading pictures directly (img-BzEzz8Kg8-163155554179776) (C:%5CUsers%5Cliuyuansong%5CDesktop%5C%E7%AC%94%E8%E8%E8%AE%B0%5C%5C%E5%89%8D%E7%BC%80%E6%E6%A0%91%E5%8C%8C%E8%B4%AA%E5%E5%E5%E5%E5%E5%EE5%83%EF%E7%E7%E7%E7%E7%E7%E7%E7%95.assets%5C1617808294645.png)]

The image above is a Trie tree representing a collection of keywords {"a", "to", "tea", "ted", "ten", "i", "in", "inn"}.

Basic properties of Trie trees:

1. The root node does not contain a character. Every child node except the root node contains a character.

(2) From the root node to a node, the characters that pass through the path are connected to form the corresponding string for that node.

(3) All the sub-nodes of each node contain different characters, which can be reused naturally.

(4) Characters that repeat continuously from the first character occupy only one node, such as to, and ten above. The repeating word t occupies only one node.

To implement a prefix tree, you need three variables, pass, end, nexts.

int pass indicates that by the number of times this node has passed, it is possible to determine that several of the joined strings are prefixed with'incoming pre'

int end denotes how many strings end with this node

TrieNode[] nexts; //The array holding the next node is not directly next node because it may be followed by more than one character

eg: next[0] ==null has no way to'a', next[0]!=Null has a way to'a'

eg: next[26] ==null has no way to'z', next[26]!=Null has a way to'z'

public class TrieTree { //Tree Node public static class TrieNode { int pass; //By the number of times this node has passed, you can tell how many times a prefix of a string has passed int end; //How many strings end with this node TrieNode[] nexts;//The array holding the next node is not directly next node because it may be followed by more than one character //eg: next[0] ==null has no way to'a'next[0]!=Null has a way to'a' //eg: next[26] ==null has no way to'z'next[26]!=Null has a way to'z' TrieNode() {//Constructor pass = 0; end = 0; nexts = new TrieNode[26]; //Initialization array up to 26 letters } } public static class Trie{ private TrieNode root; public Trie(){ root = new TrieNode(); //Initialize the root node without data to make it a puppet node } //The process of building a prefix tree public void insert(String word){ //String empty not handled if (word == null) return; char[] chs = word.toCharArray(); //Define a node to point to root TrieNode node = root; //Once you want to start hanging things on the root and stretch the road, start with ++, so the pass value on the root is how many words are entered node.pass++; for (char ch : chs) { //Converts a character to its path, subtracts'a'from ASCII, so index of a = 0, index of B = 1, and so on int index = ch - 'a'; //If there is no node beneath it, that is, no road, create a new one if (node.nexts[index] == null) node.nexts[index] = new TrieNode(); /*If so, multiplex and move to the node specified by the next The summary is that there are nodes that move directly to the next (extending down), and if not, create a new one and move again*/ node = node.nexts[index]; node.pass++; //pass++ on node properties along the way for each extension } node.end++; //End++ at the end of the loop indicates how many words end with that node } //Lookup words have been added several times public int search(String word){ if (word == null) return 0; char[] chs = word.toCharArray(); TrieNode node = root; for (char ch : chs) { int index = ch - 'a'; //Convert the characters a,b,c..To their corresponding 0, 1, 2, 3.. //When the next point does not correspond (null), return 0. For example, if there is a path abc, you want to check abcd, this path does not (as long as it is interrupted), return 0 if (node.nexts[index] == null) return 0; node = node.nexts[index]; } return node.end; //To the end is the number of times you have joined } //To delete a path is to pass--, go to the last node, and end-- public void delete(String word){ if (search(word)!=0){ //Check it again before you can continue deleting it char[] chs = word.toCharArray(); TrieNode node =root; node.pass--; //Let the root node pass first--because a word has been deleted for (char ch : chs) { int index = ch - 'a'; /*Then the pass of the corresponding node is operated on -1, and after subtracting it, we can see if it is equal to 0. If it is 0, it means that no one is going to it anymore, then we need to set it to null and disconnect all the following*/ if (--node.nexts[index].pass == 0) { node.nexts[index] = null; return; } node = node.nexts[index]; } //Now that everything is looping, the node is over. Remember to end-- node.end--; } } //Several of the added strings are prefixed with'pre' public int preNums(String pre){ if (pre == null) return 0; char[] chs = pre.toCharArray(); TrieNode node = root; for (char ch : chs) { int index = ch - 'a'; //Convert the characters a,b,c..To their corresponding 0, 1, 2, 3.. if (node.nexts[index] == null) { //The next point has no corresponding (null) and returns 0 // For example, if you have a path that is abc and you want to check that the prefix is abcd, this path does not (as long as it is broken) and returns 0 return 0; } node = node.nexts[index]; } //The pass to the end is the number of paths prefixed with prep return node.pass; } } }

# 2. Greedy algorithm

The basic idea of greedy algorithm:

1. Establish a mathematical model to describe the problem.

2. Divide the solved problem into several subproblems.

3. Solve each subproblem to obtain the local optimal solution of the subproblem.

4. Combine the local optimal solution of the subproblem into a solution of the original problem.

The premise of the greedy strategy is that the local optimal strategy can lead to the global optimal solution, which is transitive.

Techniques often used in the implementation of greedy strategies:

1. Create a comparer to sort by a criterion

2. Build a comparer to compose a heap based on a standard

General framework of greedy algorithms:

Selection function select: This is the greedy strategy, which is the key to greedy law. It indicates which candidate has the best chance of forming a solution to the problem. The selection function is usually related to the target function. For example, in the problem of finding change, greedy strategy is to select the currency with the highest par value in the candidate set.

Constraint function constraint: Check if adding a candidate to the solution set satisfies the constraint condition. For example, in the change finding problem, the constraint function is the sum of the currencies selected at each step and the currencies paid, which does not exceed the amount of the change to be found.

Greedy(C) //C is the input set or candidate set of the problem { S={ }; //Initial solution set is empty while (not solution(S)) //Set S does not form a possible solution to the problem { x=select(C); //Greedy selection in candidate set C if constraint(S, x) //Determine if constraints are satisfied when x is added to set S S=S+{x}; C=C-{x}; } return S; }

A possible solution to the problem is composed of all solution elements.

## 1. Minimum dictionary order of strings

Description: Given an array of strs of type string, find a way to stitch all strings together so that they form a string with the smallest dictionary order.

/*For example ABC > AAA C < CDA C > Ba Wrong idea: a, B a<=b, a before placing or B before placing counter example: b, B a If this means that splicing should be B B a but actually B a B is the smallest Correct: a, B a.b<=b.a before placing, otherwise B before placing (.means splicing) */ public class lowestZiDianXu { public static String lowestString(String[] strs){ if (strs == null || strs.length ==0){ return ""; } Arrays.sort(strs, new Comparator<String>() { @Override public int compare(String a, String b) { return (a + b).compareTo(b + a); //Returns 0 if the specified number is equal to the parameter. Returns -1 if the specified number is less than the parameter (in parentheses). Returns 1 if the specified number is greater than the parameter. //Comparators obj1 and obj2 are objects to compare. If the objects are equal, this method returns zero. If obj1 is greater than obj2, it returns a positive value. Otherwise, it returns a negative value. } }); String res = ""; for (int i = 0; i < strs.length; i++) { res = res + strs[i]; //Stitching } return res; } }

## 2. Scheduling of activities

Description: Some items occupy a single room for announcement. A conference room cannot hold two announcements at the same time. Give you the start and end time of each item (give you an array, which contains a specific item), you can schedule the announcement and ask the conference room to give the most announcements. Return to this maximum number of announcements.

public class BestArrange { //The structure of the meeting public static class Program{ public int start; public int end; public Program(int start, int end) { this.start = start; this.end = end; } } public static int bestArrange(Program[] programs,int start){ //Beginning Time Arrays.sort(programs, new Comparator<Program>() { @Override public int compare(Program o1, Program o2) { return o1.end - o2.end; //Top Rank with End Time Ascending, End First } }); int result = 0; for (int i = 0; i < programs.length; i++) { //The point in time at which the meeting is to be scheduled (the target point in time)<=The start of the meeting description can be arranged in a single row, perhaps idle for a while if (start <= programs[i].start){ result++; start = programs[i].end; //Update Target Time Point } } return result; } }

## 3. Cut gold bars

DESCRIPTION: A gold bar cut in half takes the same amount of copper as the length. For example, a 20-length bar, which costs 20 coppers regardless of the two halves of the length of the cut. How can a group of people divide the whole bar into the least expensive ones? For example, given an array {10,20,30}The gold bars are divided into 10,20,30=60 parts. If you first divide the gold bars with a length of 60 into 10 and 50, it will cost 60, and then the gold bars with a length of 50 into 20 and 30, it will cost 50 and a total of 110 copper plates. If you first divide the gold bars with a length of 60 into 30 and 30, it will cost 60, and then the gold bars with a length of 30 into 10 and 20, it will cost 30; if you divide the gold bars with a length of 60, it will cost 30; if you divide the gold bars with a length of 60, it will cost 30; if90 bronze plates.

Enter an array to return the minimum cost of splitting

Think: Small root heap, take two from the top each time, add them up and put them back until there is only one left in the priority queue.

//This is done with a small root heap public static int LessMoney(int[] arr){ PriorityQueue<Integer> pQ = new PriorityQueue<>(); //Put all the data in the little root heap first for (int i = 0; i < arr.length; i++) pQ.add(arr[i]); int sum = 0; int curr = 0; while (pQ.size()>1){ curr = pQ.poll() + pQ.poll(); sum += curr; pQ.add(curr); } return sum; }

## 4. Maximum amount of money you can earn from doing projects

Input: Positive array costs Positive array profits Positive k Positive W

Meaning: costs[i] denotes the cost profits[i] of Item i, which means the money (profit) that Item I can make after deducting expenses.

k means you can only do up to k projects W means your initial capital

Description: The immediate benefits you get when you finish a project can support you to go to the next project. Output: The maximum amount of money you end up earning.

Idea: Put all projects const in a small root heap (lock them), then pop up all projects with costs less than or equal to the funds at this time in the locked small root heap, and after pop-up, place the profits of the pop-up projects in a large root heap (sorted by profit order)

public class IPO { public static class IPONode{ public int costs; public int profits; public IPONode(int costs, int profits) { this.costs = costs; this.profits = profits; } } public static class MinCostComparator implements Comparator<IPONode>{ @Override public int compare(IPONode o1, IPONode o2) { return o1.costs - o2.costs; } } public static class MaxProfitsComparator implements Comparator<IPONode>{ @Override public int compare(IPONode o1, IPONode o2) { return o2.profits - o1.profits; } } public static int findMaxcCapital(int k,int W,int[] Costs,int[] Profits){ IPONode[] nodes = new IPONode[Profits.length];//Costs does, because they appear in pairs //Package project price and profit first for (int i = 0; i < Profits.length; i++) nodes[i] = new IPONode(Costs[i], Profits[i]); //Create two priority queues: profits big root heap and const small root heap PriorityQueue<IPONode> maxProfitsQ = new PriorityQueue<>(new MaxProfitsComparator()); PriorityQueue<IPONode> minCostsQ = new PriorityQueue<>(new MinCostComparator()); //To put everything first in the smallest cost means to put everything first in the small root heap for (int i = 0; i < nodes.length; i++) minCostsQ.add(nodes[i]); //Since there are only k opportunities for (int i = 0; i < k; i++) { //Minimum cost queue is not empty (locked) &&Existing capital W >=Costt of all top items can enter maximum profit Q (unlocked). This means that all items with costs less than or equal to the funds at this time will be ejected and put into the big root heap while (!minCostsQ.isEmpty() && W >= minCostsQ.peek().costs){ maxProfitsQ.add(minCostsQ.poll()); } //Once the capital chain can't keep up (maxQ is empty, it means too little money, the project can't be done), return to the existing capital W if (maxProfitsQ.isEmpty()) return W; //Otherwise, capital is the top profit of w+big root heap W = W + maxProfitsQ.poll().profits; } return W; } }

## 5. Boat crossing river

An array arr, length N and each value is positive, representing the weight of N individuals. Given a positive limit, it represents the weight of a ship. Each ship can only be two persons at most; the weight of passengers cannot exceed the limit. It will take at least a few boats to return if N individuals are crossing the river at the same time.

Think: Greedy, the lightest and heaviest groups are ordered first, then the greedy double pointer should first sort the weight of people, and then compare the weight of the largest person and the smallest person, and if they are overweight, give the heaviest ship and then compare it with the second largest person. Until all is done.

public int getBoat(int[] arr, int limit) { //Sort your weight first Arrays.sort(arr); int i = 0,j = arr.length - 1; int boatSum = 0; while(i <= j) { //If you're in the middle, there's only one person left and this person has a single boat if(i == j) { boatSum++; break; } //Give them a double pointer movement if the lightest and heaviest can form a group if(arr[i] + arr[j] <= limit) { boatSum++; i++; j--; } else {//If the lightest and heaviest can't be grouped together, give weight to a single ship j-- //Because you're the heaviest and lightest I can't match you, you can only take a boat by yourself boatSum++; j--; } } return boatSum; }

## 6. Swing Sequence

public int wiggleMaxLength(int[] nums) { if(nums.length<=1) return nums.length; int res=1;//The rightmost end is a peak //Record whether the previous pair is positive or negative If the previous positive diff is also positive, continue on the same slope or res++. //continue if the previous negative current diff is also negative int preDiff=0; for(int i=0;i<nums.length-1;i++){ int diff=nums[i+1]-nums[i]; //Explanation that a peak or valley has been encountered because the current is positive and the front may be flat or the valley has been encountered if((diff>0 && preDiff<=0) || (diff<0 && preDiff>=0)){ res++; preDiff=diff; } } return res; }

## 7. Jump Game

public boolean canJump(int[] nums) { /* //dp[i]Represents whether to jump to the current position boolean[] dp=new boolean[nums.length]; dp[0]=true; for(int i=1;i<nums.length;i++){ for(int j=i-1;j>=0;j--){ //Can jump to that position and that position can jump here if(dp[j] && nums[j]+j>=i){ dp[i]=true; break; } } } return dp[nums.length-1];*/ if (nums.length == 1) return true; // Only one element is achievable int cover=nums[0];//Maximum distance covered by the first element for(int i=1;i<nums.length;i++){ //Return directly if the maximum distance is no longer at the current location if(cover < i) return false; //If so, see if the maximum distance can be enlarged cover=Math.max(cover,nums[i]+i); } return true; }

senior No matter how greedy you jump, the coverage must be able to jump to, increase the coverage by the most steps. Once you cover the end point, you get the most steps! This requires statistics of two coverages, the coverage of the current steps is the most and the coverage of the next steps is the most

public int jump(int[] nums) { if(nums.length==1) return 0; /* dynamic programming boolean[] can=new boolean[nums.length]; int[] dp=new int[nums.length]; dp[0]=0; can[0]=true; for(int i=1;i<nums.length;i++){ dp[i]=Integer.MAX_VALUE; for(int j=i-1;j>=0;j--){ //Can jump to that position and that position can jump here if(can[j] && nums[j]+j>=i){ dp[i]=Math.min(dp[i],dp[j]+1); can[i]=true; } } } return dp[nums.length-1];*/ int curDistance = 0; // Maximum distance currently covered int res = 0; int nextDistance = 0; // The furthest distance covered by the next step for (int i = 0; i < nums.length - 1; i++) { nextDistance = Math.max(nums[i] + i, nextDistance); // Update the furthest distance covered by the next step if (i == curDistance) { // Currently is the furthest distance covered curDistance = nextDistance; // Update current maximum coverage distance res++; } } return res; }

## 8. Gas stations

Force Button Address The analogy is that there are n stations on a circular road; each station has a good person or a bad person; the good person gives you money and the bad person charges you for the toll. If you don't have enough money to pay the toll, the bad person chops you to death. Ask: From which station can you walk around and live back to your starting point?

First of all, consider the case that if all the good people give you less than the bad people's toll combined, there will always be a time when you don't have enough money to pay the toll and your end result will be chopped up.

Choose the right place if you have enough money. If you choose a start at random, then you will definitely start with a site with good people, because at the beginning you had no money and the bad people could only be chopped to death; now you start at the start, reach the end of a site, and be chopped to death by the bad people at the end of the site, you are[start, end] doesn't have enough money to pay the end-point bad person's toll because the start site is a good person, so at (start, end) If you start at any point in the document, you will save less money than you do now, or will be chopped down by the bad guys at the end site. So you read the file again and make smart choices to start at end+1 and continue your solemn journey. Finally one day, you find that you have reached the last site without being chopped down.

At this point of thought, I'm moving on, and I don't have enough money to keep you going to Start? Of course, since it was judged at the beginning that the amount of money a good person gives you is greater than or equal to the toll a bad person needs, and the money you've saved now is enough to pay the toll a bad person charges you

class Solution { //Method 2 o(n) public int canCompleteCircuit(int[] gas, int[] cost) { int gasSum=0; //gas[i]-cost[i] represents the current position to the next position The remaining oil does not want to open a new array I've just overwritten the previous value here for (int i = 0; i < gas.length; i++){ gas[i]=gas[i]-cost[i]; gasSum+=gas[i]; } if(gasSum<0) return -1;//If the total remaining oil is less than 0, you can't run at all. int sum=0,start=0; //Explaining that you can run away from the topic also means that you have a unique solution for (int i = 0; i < gas.length; i++) { sum+=gas[i]; if(sum<0){ start=i+1; sum=0; } } return start; } }

## 9. Candy Divide (Cowdriver Focus)

Force buckle Cowdriver This question must be to determine the sides before determining another one, for example, the left side of each child, and then the right side. If both sides are considered together, one dimension will be determined before another dimension is determined.

Determine the right-to-left situation (traverse from front to back) and then the left-to-right situation (from back to front)

Be sure to take a large value from back to front, so take the number of need[i + 1] + 1 and need[i]. Only need[i] takes the most to keep both the number of left need[i - 1] and the number of right need[i + 1]

public int candy (int[] arr) { int[] need=new int[arr.length]; need[0]=1;//Default first point 1 candy //From left to right, find the best solution to assign when the right side is larger than the left side for(int i=1;i<arr.length;i++){ //Bigger than the front is one more candy if(arr[i]>arr[i-1]) need[i]=need[i-1]+1; else need[i]=1;//Divide up a candy if it is less than or equal to the front } //Go back and forth to find the best solution when the left side is larger than the right side for(int i=arr.length-2;i>=0;i--){ //Larger than the latter is one more candy than the latter and two more candy than the former is enough to satisfy the instructions. if(arr[i]>arr[i+1]) need[i]=Math.max(need[i],need[i+1]+1); } int res=0; for(int num:need) res+=num; return res; }

## 10. Rebuild Queues Based on Height

Force Button Address : Consider one dimension before the other directly inserting according to the subscript when using the same two dimensions

public int[][] reconstructQueue(int[][] people) { //Height Ranking from High to Low Arrays.sort(people, new Comparator<int[]>() { public int compare(int[] person1, int[] person2) { if (person1[0] != person2[0]) return person2[0] - person1[0]; else return person1[1] - person2[1]; }}); List<int[]> ans = new ArrayList<int[]>(); for (int[] person : people) { ans.add(person[1], person); } return ans.toArray(new int[ans.size()][]); }

## 11. Arrow balloons (11-14 are all interval greedy)

public int findMinArrowShots(int[][] points) { //Arrange from small to large Arrays.sort(points, (o1, o2) -> o1[0]-o2[0]); int res=1;//Less need for Musk Arrow for (int i = 1; i < points.length; i++) { //The second and first cannot be touched, the first needs to be shot alone if(points[i][0]>points[i-1][1]) res++; else //Ball i and ball i-1 coincide next to interval to update coincident right boundary points[i][1]=Math.min(points[i-1][1],points[i][1]); } return res; }

## 12. Non-overlapping intervals

Force buckle : Processing repetition intervals in the same order as above

public int eraseOverlapIntervals(int[][] intervals) { //Arrange from small to large Arrays.sort(intervals,(o1, o2) -> o1[0]-o2[0]); int res=0,preEnd=intervals[0][1]; for (int i = 1; i < intervals.length; i++) { //Continue updating preEnd end position coordinates if second and first are not contaminated if(intervals[i][0]>=preEnd) { preEnd=intervals[i][1]; } else {//If i and i-1 coincide next to an interval, delete the one with the longest interval length preEnd=Math.min(preEnd,intervals[i][1]); res++; } } return res; }

## 13. Section letter

Force buckle : counts the position of the last occurrence of each character, then traverses the character from the beginning, and updates the character's farthest occurrence subscript. If the character's farthest occurrence location subscript and the current subscript are equal, the split point is found

public List<Integer> partitionLabels(String s) { int[] map=new int[26];//a..z //Count the farthest distance each character appears for (int i = 0; i < s.length(); i++) map[s.charAt(i)-'a']=i; List<Integer> res = new ArrayList<>(); int right=0,start=0; for (int i = 0; i < s.length(); i++) { int len=map[s.charAt(i)-'a'];//Get the farthest distance of the current character right=Math.max(len,right);//Take the furthest distance // If you've reached the last length you can divide at your current location if(i==right){ res.add(i-start+1); start=i+1;//Start a new series of divisions } } return res; }

## 14. Consolidation interval (bull focus)

//Force button answer public int[][] merge(int[][] intervals) { //Sort by starting position Arrays.sort(intervals,(o1,o2)->o1[0]-o2[0]); List<int[]> list=new ArrayList<>(); int start=intervals[0][0],preEnd=intervals[0][1]; for (int i = 1; i < intervals.length; i++) { //When two intervals overlap, merge them and update the rightmost boundary of the merged interval if(intervals[i][0]<=preEnd){ intervals[i][1]=Math.max(intervals[i][1],preEnd); preEnd=intervals[i][1]; } else {//Add i-1 without overlapping list.add( new int[]{start,preEnd}); //Re-update start and end locations start=intervals[i][0]; preEnd=intervals[i][1]; } } list.add( new int[]{start,preEnd});//Add the last group return list.toArray(new int[0][]); } //Cowdriver Answer public ArrayList<Interval> merge(ArrayList<Interval> intervals) { //Sort by interval initial order Collections.sort(intervals,(( o1,o2) -> o1.start-o2.start)); ArrayList<Interval> res= new ArrayList<>(); if(intervals.size()==0) return res; int start=intervals.get(0).start,preEnd=intervals.get(0).end; for (int i = 1; i < intervals.size(); i++) { Interval curInterval = intervals.get(i); //Update the farthest distance the coincidence can reach if the current start is less than the previous end note encounters coincidence if(curInterval.start<=preEnd) preEnd=Math.max(preEnd,curInterval.end); else {//Explanation does not coincide then add element res.add(new Interval(start,preEnd)); //Start a new interval start=curInterval.start; preEnd=curInterval.end; } } res.add(new Interval(start,preEnd)); return res; }

();

if(intervals.size()==0) return res;

int start=intervals.get(0).start,preEnd=intervals.get(0).end;

for (int i = 1; i < intervals.size(); i++) {

Interval curInterval = intervals.get(i);

//Update the farthest distance the coincidence can reach if the current start is less than the previous end note encounters coincidence

if(curInterval.start<=preEnd)

preEnd=Math.max(preEnd,curInterval.end);

else {// description does not coincide then add element

res.add(new Interval(start,preEnd));

//Start a new interval

start=curInterval.start;

preEnd=curInterval.end;

}

}

res.add(new Interval(start,preEnd));

return res;

}