Title address: https://leetcode-cn.com/study-plan/lcof/?progress=xcewnbs
summary
When looking for the middle node of the chain table, use the fast and slow pointers, when both the fast and slow pointers are initially pointing to the head, the end condition cannot be
while(fast!=null&&fast.next!=null)
Because of this, if I judge that 1, 2, 3, 1, 3, [3, 4] finds 4, my solution is to initially point the fast pointer at the next node of the head node
ListNode fast=head.next; ListNode slow=head;
If the value of hashMap is a List, how to assign all values to List<List>
new ArrayList<List<String>>(map.values());
When simulating a stack with an array, remember to set the top of the stack to -1;
list inversion, Collections.reverse();
Get Queue Header Element of Queue
queue.peek()/queue.element()
java array to list
int temp1[]=queue.poll(); List<Integer> list1 = Arrays.asList(temp1[0],temp1[1]); list.add(list1);
2021.08.06 Day 1 Integer
1 Swordfinger Offer II 001.Integer Division
Given two integers a and b, the quotient a/b for dividing them requires that the multiplication sign'*', the division sign'/'and the remainder sign'%' not be used.
class Solution { public int divide(int a, int b) { if(a==0x80000000&&b==-1)//Overflow, -2^31/-1 return 0x7FFFFFFF; int positive=2;//Number of positive numbers marked if(a>0){ positive--; a=-a; } if(b>0){ positive--; b=-b; } int result=0; //Divide two negative numbers while(a<=b){ a=a-b; result++; } return positive==1?-result:result; } }
optimization
Problem Analysis: When the dividend is large but the dividend is small, the subtraction operation will be performed many times. For example, 2^31/1 performs 2^31 subtractions.
When the dividend is greater than the divisor, continue comparing to determine if the dividend is greater than twice the divisor. If so, continue to determine if the dividend is greater than four, eight, 16 times the dividend,... If the dividend is at most two times the dividend, then the dividend will be subtracted by two times the dividend, and then repeat the remaining dividends in the previous steps.
In order to find 15/2 quotients, first subtract 8 (2^3) from 15 to get 7; Subtract 4 (2^2) from 7 to get 3; Then subtract 2 (2^1) from 3 to get 1, where 1 is less than 2, so the quotient is 3+2+1=7
class Solution { public int divide(int dividend, int divisor) { //-2^31/ -1 = 2^31 overflow if(dividend == 0x80000000 && divisor == -1){ return 0x7FFFFFFF; } int negative = 2;//Used to record positive numbers //Since negative numbers go beyond the bounds of -2^31 -> 2^31, positive numbers are used to go negative. if(dividend > 0){ negative --; dividend = -dividend; } if(divisor > 0){ negative --; divisor = -divisor; } //Divide two negative numbers int result = 0; while(dividend <= divisor){ int value = divisor;//Statistical subtraction int quotient = 1;//Statistical quotient while(value > 0xc0000000 && value + value >= dividend){//Value > 0xc0000000 to prevent value*2 from overflowing quotient += quotient;//If you can multiply quotient*=2 value += value;//If you can multiply value*=2 } result += quotient; dividend -= value; } return negative == 1 ? -result : result; } }
0xc0000000 represents half (-2^31)/2 of the smallest negative integer of 32-bit int type. Since both dividends and dividends have been converted to negative numbers, the form of the above judgment is that dividends are greater than dividends.
Reference resources
Swordfinger Offer II 001.Integer Division
Method 2:
Quick Bit Division
class Solution { public int divide(int a, int b) { int signBit = 0x80000000; long ans = 0, x = a, y = b; //Math.abs() is not used directly to avoid divisions or -2^31, where Math.abs() returns with an error x = x < 0 ? -x : x; y = y < 0 ? -y : y; //Example: 60/8=(60-32)/8+4=(60-32-16)/8+2+4=(60-32-16-8)/8+1+2+4=1+2+4=7 while (x >= y) { long cnt = 1, base = y; while (x > (base << 1)) { cnt <<= 1; base <<= 1; } ans += cnt; x -= base; } ans = (((a ^ b) & signBit) == 0) ? ans : -ans; return (int) ((Integer.MAX_VALUE < ans || ans < Integer.MIN_VALUE) ? Integer.MAX_VALUE : ans); } }
2 Swordfinger Offer II 002.Binary Addition
Given two 01 strings a and b, calculate their sum and output as binary strings.
The input is a non-empty string and contains only the numbers 1 and 0.
class Solution { public String addBinary(String a, String b) { int len1=a.length(); int len2=b.length(); //If the length of the string is different, precede the shorter string with 0 if(len1>len2){ for(int i=0;i<len1-len2;i++) { b="0"+b; } } if(len1<len2) { for(int i=0;i<len2-len1;i++) { a="0"+a; } } len1=a.length(); len2=b.length(); int len3=len1+1; int arr[]=new int[len3];//The result of the addition may be one more place than the original string int carry=0; len3=len3-1; len1=len1-1; len2=len2-1; while(len1>=0&&len2>=0){ if( a.charAt(len1)=='1'&&b.charAt(len2)=='1') { if(carry==1)//Carry-1 scenario arr[len3]=1; else arr[len3]=0; carry=1;//After calculation, the carry is 1 } else if(a.charAt(len1)=='0'&&b.charAt(len2)=='0') { arr[len3]=carry; carry=0;//After calculation, carry is 0 } else{ if(carry==1) arr[len3]=0; else arr[len3]=1; //Carry position does not change after calculation } len1--; len2--; len3--; } arr[0]=carry;//Add rounding to the first element of arr String str=""; if(arr[0]==1) str="1"; for(int i=1;i<arr.length;i++)//Split String str+=arr[i]; return str; } }
Solution 2: The reason is the same, but very simple
Reference resources: Binary Sum
class Solution { public String addBinary(String a, String b) { StringBuffer ans = new StringBuffer(); int n = Math.max(a.length(), b.length()), carry = 0; for (int i = 0; i < n; ++i) { carry += i < a.length() ? (a.charAt(a.length() - 1 - i) - '0') : 0; carry += i < b.length() ? (b.charAt(b.length() - 1 - i) - '0') : 0; ans.append((char) (carry % 2 + '0')); carry /= 2; } if (carry > 0) { ans.append('1'); } ans.reverse(); return ans.toString(); } }
3 Swordfinger Offer II 003.Number of 1 of the first n digit binaries
class Solution { public int[] countBits(int n) { int[] res = new int[n+1]; for(int i=1;i<n+1;i++) res[i] = res[i>>1] + (i%2); return res; } }
class Solution { public int[] countBits(int n) { int[] bits = new int[n + 1]; for (int i = 1; i <= n; i++) { bits[i] = bits[i & (i - 1)] + 1; } return bits; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode-solution-0t1i/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
class Solution { public int[] countBits(int n) { int[] bits = new int[n + 1]; for (int i = 0; i <= n; i++) { bits[i] = countOnes(i); } return bits; } public int countOnes(int x) { int ones = 0; while (x > 0) { x &= (x - 1); ones++; } return ones; } }
2021.08.07 Day 2 Integer
4 Swordfinger Offer II 004. Numbers that occur only once
Give you an array of integers, nums, where each element occurs exactly three times except once. Find out and return the element that occurs only once.
Idea 1: Hash tables, map elements and the number of occurrences of that element, and finally traverse
Idea 2: Bit operation
If one number occurs once and the other books occur twice, then we can do exclusive or operations on the elements of the entire array, and the result is a number that occurs only once
Now that the other numbers appear three times, we can consider adding up each binary bit of all the numbers separately
Because three duplicate numbers, their binary bits are the same, add up to either 0 or 3. If you don't duplicate the binary bits of that number, they may become 0 or 4. We take a module of 3 and the binary bits of the duplicate number.
How do I get the nth binary bit of each number?
Consider moving this number one bit to the right and then one bit with it (for example, 1011, take the second binary bit, note that the rightmost is the first binary bit, 1011 shifts one bit to the right to 0101,0101&0001=1, and this binary bit is taken out
So, take out the formula for the nth binary bit of a number
x>>(n-1)&1
What do I do when I get the modeled value?
Initialize the result to 0, for example, if the first binary bit is 1, then you only need to add or add the result to the value of the left shift of 0 bits, which means to keep all binary 1's as
If the third binary bit is 1, then you only need to phase the result with the value (0100) moved 2 bits to the left.
class Solution { public int singleNumber(int[] nums) { int result=0; for(int i=0;i<32;i++) { int temp=0; for(int j=0;j<nums.length;j++) { temp+=(nums[j]>>i)&1; } if(temp%3!=0) result|=(1<<i); } return result; } }
5 Swordfinger Offer II 005. Maximum product of word length
Given a string array words, calculate the maximum product of the length of words[i] and words[j] when they do not contain the same character. Assume that the string contains only lowercase letters in English. If there is no pair of strings that do not contain the same character, return 0.
Idea 1: Violent enumeration (which will time out), for each string, enumerate its combination with the string after it to see if there are duplicate characters, or calculate the length product of both
class Solution { public int maxProduct(String[] words) { int max=0; for(int i=0;i<words.length;i++){ for(int j=i;j<words.length;j++){ if(!isSame(words[i],words[j])){ max=Math.max(max,words[i].length()*words[j].length()); } } } return max; } public boolean isSame(String a,String b){ for(int i=0;i<a.length();i++){ for(int j=0;j<b.length();j++){ if(a.charAt(i)==b.charAt(j)) return true; } } return false; } }
Idea 2: Bit operation
Consider how to reduce the complexity of comparing two strings to see if they have the same character. You can convert a string to an integer, such as
When a appears, the conversion to an integer is result|=1< 0
Appear z, result |=1< 25
Comparing two strings to see if they have the same character can be converted to comparing whether the corresponding integer of the two strings is 0 and 0, indicating that the characters contained in the two strings are not duplicated (in binary bit, the number in binary bit 1 is just wrong).
Reference resources: Clever use of the first 26 bits of integers to store 26 letters
public static int maxProduct2(String[] words) { int length = words.length; int[] ints = new int[length]; for (int i = 0; i < length ; i++) { for (char c : words[i].toCharArray()){ ints[i] |= (1 << (c - 97));//Use integers to represent a string in word } } int re = 0; for (int i = 0; i < length -1 ; i++) {//Compare integers and get the maximum length int pre1 = ints[i]; for (int j = i + 1; j < length; j++) { int pre2 = ints[j]; if ((pre1 & pre2) == 0){//And operation int te = words[i].length() * words[j].length(); re = re >= te ? re : te; } } } return re; } Author: closes Links: https://leetcode-cn.com/problems/maximum-product-of-word-lengths/solution/qiao-miao-di-shi-yong-zheng-xing-shu-de-vec14/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
6 Swordfinger Offer II 006. Sum of two numbers in a sorted array
Solution ideas: double pointer to end
Head+tail <target means not enough additions, move i back
Head + tail > target shows how much the additive number is, move j forward
class Solution { public int[] twoSum(int[] numbers, int target) { int i=0;int j=numbers.length-1; while(i<j){ if(numbers[i]+numbers[j]<target) i++; else if (numbers[i]+numbers[j]>target) j--; else return new int[]{i,j}; } return null; } }
Idea 2: Binary search
Find two numbers in the array so that their sum is equal to the target value. First fix the first number, then look for the second number, which is equal to the target value minus the difference of the first number. Using the ordered nature of arrays, the second number can be found by means of binary search. To avoid repetitive searches, only search to the right of the first number when searching for the second number.
class Solution { public int[] twoSum(int[] numbers, int target) { for (int i = 0; i < numbers.length; ++i) { int low = i + 1, high = numbers.length - 1; while (low <= high) { int mid = (high - low) / 2 + low; if (numbers[mid] == target - numbers[i]) { return new int[]{i + 1, mid + 1}; } else if (numbers[mid] > target - numbers[i]) { high = mid - 1; } else { low = mid + 1; } } } return new int[]{-1, -1}; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/solution/liang-shu-zhi-he-ii-shu-ru-you-xu-shu-zu-by-leet-2/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
2021.08.08 Day 3 Array
7 Swordfinger Offer II 007.Three Numbers with a Neutral of 0 in the Array
Given a n array of nums containing n integers, determine if there are three elements a, b, c in nums such that a + b + c = 0? Find all ternaries that sum to 0 and are not duplicated.
Think: Note that you want to find non-repeating tuples. If you traverse with violence, you will inevitably find duplicate tuples.
So let's consider sorting the arrays first
First, position a number one at a time in the outer loop. The inner loop is twoSum equivalent to a sorted array. Use double pointers. To avoid duplication, the outer loop should skip the same elements each time.
Overall, the first plus is fixed, the second plus is fixed, and the third plus is solved with a double pointer.
class Solution { public List<List<Integer>> threeSum(int[] nums) { Arrays.sort(nums); List<List<Integer>> result=new ArrayList(); for(int i=0;i<nums.length;i++) { if(i>0&&nums[i]==nums[i-1]) continue; //Skip the same number int k=nums.length-1; for(int m=i+1;m<nums.length;m++){ if(m>i+1&&nums[m]==nums[m-1]) continue; //Skip the same number while(m<k){ if(nums[m]+nums[k]>0-nums[i]) k--;///Add larger, right pointer forward else if(nums[m]+nums[k]<0-nums[i]) break; //Because we have fixed the left pointer, the left pointer cannot move, adding up smaller cases is not satisfactory, break directly else{ List<Integer>list=new ArrayList();//Notice where the list was created list.add(nums[i]); list.add(nums[m]); list.add(nums[k]); result.add(list); break; } } } } return result; } }
The official solution will be faster
class Solution { public List<List<Integer>> threeSum(int[] nums) { int n = nums.length; Arrays.sort(nums); List<List<Integer>> ans = new ArrayList<List<Integer>>(); // Enumeration a for (int first = 0; first < n; ++first) { // Requires a different number from the last enumeration if (first > 0 && nums[first] == nums[first - 1]) { continue; } // The pointer corresponding to c initially points to the rightmost end of the array int third = n - 1; int target = -nums[first]; // Enumeration b for (int second = first + 1; second < n; ++second) { // Requires a different number from the last enumeration if (second > first + 1 && nums[second] == nums[second - 1]) { continue; } // You need to make sure that the pointer for b is on the left side of the pointer for c while (second < third && nums[second] + nums[third] > target) { --third; } // If pointers coincide, increase with b // There will be no C that satisfies a+b+c=0 and b<c, so you can exit the loop if (second == third) { break; } if (nums[second] + nums[third] == target) { List<Integer> list = new ArrayList<Integer>(); list.add(nums[first]); list.add(nums[second]); list.add(nums[third]); ans.add(list); } } } return ans; } }
class Solution { public static List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> ans = new ArrayList(); int len = nums.length; if(nums == null || len < 3) return ans; Arrays.sort(nums); // sort for (int i = 0; i < len ; i++) { if(nums[i] > 0) break; // If the current number is greater than 0, the sum of the three must be greater than 0, so end the cycle if(i > 0 && nums[i] == nums[i-1]) continue; // Duplicate removal int L = i+1; int R = len-1; while(L < R){ int sum = nums[i] + nums[L] + nums[R]; if(sum == 0){ ans.add(Arrays.asList(nums[i],nums[L],nums[R])); while (L<R && nums[L] == nums[L+1]) L++; // Duplicate removal while (L<R && nums[R] == nums[R-1]) R--; // Duplicate removal L++; R--; } else if (sum < 0) L++; else if (sum > 0) R--; } } return ans; } }
L++ and R after weight removal - because L and R point to the same number as the previous one at this time
It's really amazing. Please close my knee
8 Swordfinger Offer II 008. and shortest subarray greater than or equal to target
Given an array of n positive integers and a target of positive integers.
Find the contiguous subarray [numsl, numsl+1,..., numsr-1, numsr] in the array that satisfies its minimum length and is greater than or equal to the target and return its length. Returns 0 if no qualifying subarray exists.
Idea 1: After the obtained and satisfied conditions >= target, record the current length, then move the left pointer to the right to see if it is still satisfied, until it is not, and then move the right pointer back
class Solution { public int minSubArrayLen(int target, int[] nums) { int left = 0; int min = nums.length + 1; int sum = nums[left]; if (sum > target) return 1; for (int i = 1; i <= nums.length - 1; i++) { sum += nums[i]; while (sum >= target) { min = Math.min(min, i - left + 1); sum = sum - nums[left]; left++; } } return min>nums.length?0:min; } }
class Solution { public int minSubArrayLen(int s, int[] nums) { int lo = 0, hi = 0, sum = 0, min = Integer.MAX_VALUE; while (hi < nums.length) { sum += nums[hi++]; while (sum >= s) { min = Math.min(min, hi - lo); sum -= nums[lo++]; } } return min == Integer.MAX_VALUE ? 0 : min; } }
Idea 2: Resolving Violence
class Solution { public int minSubArrayLen(int s, int[] nums) { int n = nums.length; if (n == 0) { return 0; } int ans = Integer.MAX_VALUE; for (int i = 0; i < n; i++) { int sum = 0; for (int j = i; j < n; j++) { sum += nums[j]; if (sum >= s) { ans = Math.min(ans, j - i + 1); break; } } } return ans == Integer.MAX_VALUE ? 0 : ans; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/minimum-size-subarray-sum/solution/chang-du-zui-xiao-de-zi-shu-zu-by-leetcode-solutio/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
9 Swordfinger Offer II 009. Subarrays whose product is less than K
Given a positive integer array nums and an integer k, find the number of consecutive subarrays within the array whose product is less than k.
Train of thought: Traverse the cumulative product from left to right, if the product is less than k, continue to multiply, if it is greater than k, set the result to 1, move the left pointer one bit backward, and multiply from the left pointer
For example, input: nums = [10,5,2,6], k = 100, which in turn traverses 10, 10*5, 10*5*2, 5*2, 5*2, 5*2*6
8 of 2, 2 * 6, 6
class Solution { public int numSubarrayProductLessThanK(int[] nums, int k) { int lo=1;int hi=0; int n=nums.length;int product=1; int result=0; while(hi<n){ product*=nums[hi++]; if(product<k){ result++; if(hi==n){//hi has reached the end and needs to be handled, otherwise the loop condition is not satisfied and the loop ends product=1; hi=lo++; } } else{ product=1; hi=lo++; } } return result; } }
Idea 2: Consider the number of subarrays that end with each array element and add them together
class Solution { public int numSubarrayProductLessThanK(int[] nums, int k) { if (k <= 1) return 0; int prod = 1, ans = 0, left = 0; for (int right = 0; right < nums.length; right++) { prod *= nums[right]; while (prod >= k) prod /= nums[left++]; ans += right - left + 1; } return ans; } }
2021.08.09 Array of Day 4
10 Swordfinger Offer II 010.and a subarray of k
Given an array of integers and an integer k, find the number of consecutive subarrays that sum to K in the array.
Think: I want to use a sliding window, but there's too much detail and I've written a lot of scrap code
Look at others
1 Violence
public class Solution { public int subarraySum(int[] nums, int k) { int count = 0; for (int start = 0; start < nums.length; start++) { int sum = 0; for (int end = start; end >= 0; end--) { sum += nums[end]; if (sum == k) { count++; } } } return count; } }
2 Prefix and + hash table optimization
public class Solution { public int subarraySum(int[] nums, int k) { int count = 0, pre = 0; HashMap < Integer, Integer > mp = new HashMap < > (); mp.put(0, 1); for (int i = 0; i < nums.length; i++) { pre += nums[i]; if (mp.containsKey(pre - k)) { count += mp.get(pre - k); } mp.put(pre, mp.getOrDefault(pre, 0) + 1); } return count; } }
11 Swordfinger Offer II 011.0 and 1 subarray of the same number
Given a binary array nums, find the longest continuous subarray with the same number of 0 and 1 and return the length of the subarray.
Prefix and Ah Ah Ah
12 Swordfinger Offer II 012. Equality of left and right subarrays
13 Swordfinger Offer II 013. Sum of 2-D Submatrices
2021.08.10 Day 5 Array
14 Swordfinger Offer II 014. Variants in strings
Solution ideas: Slide window, store the number of occurrences of characters in the sliding window with two arrays, and compare if two arrays are equal each time you slide
class Solution { public boolean checkInclusion(String s1, String s2) { if(s1.length()>s2.length()) return false; int nums1[]=new int [26]; int nums2[]=new int[26]; for(int i=0;i<s1.length();i++) nums1[s1.charAt(i)-'a']+=1; int left=0; int right=s1.length()+left-1; for(int i=0;i<=right;i++) nums2[s2.charAt(i)-'a']+=1; if(isEqual(nums1,nums2)) return true; while(right<s2.length()){ nums2[s2.charAt(left++)-'a']--; right++; if(right==s2.length()) return false; nums2[s2.charAt(right)-'a']++; if(isEqual(nums1,nums2)) return true; } return false; } public boolean isEqual(int nums1[],int nums2[]){ for(int i=0;i<nums1.length;i++){ if(nums1[i]!=nums2[i]) return false; } return true; } }
15 Swordfinger Offer II 015. All Variants in String
Given two strings s and p, find the substrings of the modifiers for all P in s and return the starting index of those substrings. Do not consider the order in which answers are output.
Variants refer to strings with the same letters but arranged differently.
The idea is to change the code of Question 14 and add the left index to the list where it meets the criteria
class Solution { List<Integer>list=new ArrayList(); public List<Integer> findAnagrams(String s, String p) { return find(p,s); } public List<Integer> find(String s1,String s2){ if(s1.length()>s2.length()) return list; int nums1[]=new int [26]; int nums2[]=new int[26]; for(int i=0;i<s1.length();i++) nums1[s1.charAt(i)-'a']+=1; int left=0; int right=s1.length()+left-1; for(int i=0;i<=right;i++) nums2[s2.charAt(i)-'a']+=1; if(isEqual(nums1,nums2)) list.add(left); while(right<s2.length()){ nums2[s2.charAt(left++)-'a']--; right++; if(right==s2.length()) break; nums2[s2.charAt(right)-'a']++; if(isEqual(nums1,nums2)) list.add(left); } return list; } public boolean isEqual(int nums1[],int nums2[]){ for(int i=0;i<nums1.length;i++){ if(nums1[i]!=nums2[i]) return false; } return true; } }
class Solution { public List<Integer> findAnagrams(String s, String p) { int n = s.length(), m = p.length(); List<Integer> res = new ArrayList<>(); if(n < m) return res; int[] pCnt = new int[26]; int[] sCnt = new int[26]; for(int i = 0; i < m; i++){ pCnt[p.charAt(i) - 'a']++; sCnt[s.charAt(i) - 'a']++; } if(Arrays.equals(sCnt, pCnt)){ res.add(0); } for(int i = m; i < n; i++){ sCnt[s.charAt(i - m) - 'a']--; sCnt[s.charAt(i) - 'a']++; if(Arrays.equals(sCnt, pCnt)){ res.add(i - m + 1); } } return res; } }
I understand
It is important to note that after a match, the left pointer cannot immediately move after the right pointer, because it may be possible to match the left and right by moving one or two positions at the same time.
class Solution { public List<Integer> findAnagrams(String s, String p) { int n = s.length(), m = p.length(); List<Integer> res = new ArrayList<>(); if(n < m) return res; int[] pCnt = new int[26]; int[] sCnt = new int[26]; for(int i = 0; i < m; i++){ pCnt[p.charAt(i) - 'a'] ++; } int left = 0; for(int right = 0; right < n; right++){ int curRight = s.charAt(right) - 'a'; sCnt[curRight]++; while(sCnt[curRight] > pCnt[curRight]){ int curLeft = s.charAt(left) - 'a'; sCnt[curLeft]--; left++; } if(right - left + 1 == m){ res.add(left); } } return res; } }
16 Swordfinger Offer II 016. Longest substring without duplicate characters
Given a string s, find out the length of the longest continuous substring that does not contain duplicate characters.
The sliding window method described below is not considered
class Solution { public int lengthOfLongestSubstring(String s) { if(s.length()==0) return 0; int left=0; int nums[]=new int[128]; int max=0; for(int right=0;right<s.length();right++){ int cur=s.charAt(right)-32; nums[cur]++; if(nums[cur]>1){//Duplicate character appears max=Math.max(max,right-left);//Keep the length before the current occurrence of duplicate characters while(nums[cur]>1){//Move the left pointer back until there are no duplicate characters between left and right int remove=s.charAt(left)-32;//32 is ASCII for space, that is, all characters have ASCII code after 32 nums[remove]--;//After the left pointer moves, the corresponding character maps to the position in the array minus 1 left++;//Left Pointer Backward } } } max=Math.max(max,s.length()-left);//This is when the right pointer moves to the end without duplicate characters. Discuss it separately return max; } }
For other solutions, refer to: leetcode 3. Longest substring without duplicate characters
2021.08.11 Day 6 String
17 Swordfinger Offer II 017. Shortest string containing all characters
18 Swordfinger Offer II 018. Valid palindromes
Given a string s, verify that s is a palindrome string, considering only alphabetic and numeric characters, ignoring case.
In this topic, an empty string is defined as a valid palindrome string.
Solution ideas: double pointer
class Solution { public boolean isPalindrome(String s) { int n = s.length(); int left = 0, right = n - 1; while (left < right) { while (left < right && !Character.isLetterOrDigit(s.charAt(left))) { ++left; } while (left < right && !Character.isLetterOrDigit(s.charAt(right))) { --right; } if (left < right) { if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) { return false; } ++left; --right; } } return true; } }
19 Swordfinger Offer II 019. Delete at most one character to get palindrome
Given a non-empty string s, determine whether deleting at most one character from the string will result in a palindrome string.
class Solution { int del = 0; //Record the number of characters deleted public boolean validPalindrome(String s) { int i = 0,j = s.length()-1; while(i < j){ if(s.charAt(i) == s.charAt(j)){ i++; j--; }else{ //If not, delete the left or right character before judging. If deleted once, it is not a palindrome string if(del == 0){ del++; return validPalindrome(s.substring(i,j)) || validPalindrome(s.substring(i+1,j+1)); } return false; } } return true; } }
20 Swordfinger Offer II 020. Number of palindrome substrings
Given a string s, calculate how many palindrome substrings are in this string.
Substrings with different starting or ending positions, even if they consist of the same character, are considered different substrings.
thinking
The number of I-centered and (i,i+1) centered outward spreading palindromes is calculated and added.
class Solution { public int countSubstrings(String s) { int result=0; for(int i=0;i<s.length();i++) result+=palindrome( s, i)+palindrome(s, i,i+1); return result; } public int palindrome(String s,int i){//i-centric palindrome string int count=1;//A single character is also a palindrome int left=i-1; int right=i+1; while(left>=0&&right<s.length()&&(s.charAt(left)==s.charAt(right))){ left--; right++; count++; } return count; } public int palindrome(String s,int i,int j){//i,j-centric palindrome string if(j>=s.length()||s.charAt(i)!=s.charAt(j)) return 0; int count=1;//It i s also a palindrome when s.charAt(i)=s.charAt(j) int left=i-1; int right=j+1; while(left>=0&&right<s.length()&&(s.charAt(left)==s.charAt(right))) { left--; right++; count++; } return count; } }
Can be simplified with only one central extension function
class Solution { public int countSubstrings(String s) { int result=0; for(int i=0;i<s.length();i++) result+=palindrome( s, i,i)+palindrome(s, i,i+1); return result; } public int palindrome(String s,int i,int j){//i,j-centric palindrome string if(j>=s.length()||s.charAt(i)!=s.charAt(j)) return 0; int count=1;//It i s also a palindrome when s.charAt(i)=s.charAt(j) int left=i-1; int right=j+1; while(left>=0&&right<s.length()&&(s.charAt(left)==s.charAt(right))) { left--; right++; count++; } return count; } }
Almost, a little more concise
public class Solution { public int countSubstrings(String s) { int ans = 0; for(int i=0;i<s.length();i++) ans+=CountSubstringsInternal(s,i,i)+CountSubstringsInternal(s,i,i+1); return ans; } public int CountSubstringsInternal(String s, int l, int r) { int cnt=0; while(l>=0&&r<s.length()) { if(s.charAt(l--)!=s.charAt(r++)) break; cnt++; } return cnt; } }
Idea 2: Dynamic planning
Reference resources: Dynamic Planning and Central Diffusion Solutions
public int countSubstrings(String s) { int length = s.length(); boolean[] dp = new boolean[length]; int count = 0;//Number of palindrome strings for (int j = 0; j < length; j++) { for (int i = 0; i <= j; i++) { if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1])) { dp[i] = true; count++; } else { dp[i] = false; } } } return count; } Author: sdwwld Links: https://leetcode-cn.com/problems/palindromic-substrings/solution/shu-ju-jie-gou-he-suan-fa-dong-tai-gui-h-3bms/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
2021.08.12 7th Day Chain List
21 Swordfinger Offer II 021. Delete the last nth node of the list of chains
Idea 1: Using recursion
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { int num=help( head,n); return num==n?head.next:head; } public int help(ListNode head,int n){ if(head==null) return 0;//0th Last Node int num= help(head.next,n);//head.next is the last node if(num==n) head.next=head.next.next;//Delete the last n nodes, n has said greater than 0, do not consider null pointers here return 1+num; } }
Idea 2: Iteration, iteration has been written many times, with the fast pointer, the fast pointer first takes n steps, and then the two pointers walk together. When the fast pointer reaches the end, both pointers take length-n steps, so the board can delete the next node of the node that the slow pointer points to.
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode fast=head; ListNode slow=head; while(n>0){ fast=fast.next; n--; } if(fast==null)//The header node to be deleted return head.next; while(fast.next!=null){ fast=fast.next; slow=slow.next; } slow.next=slow.next.next; return head; } }
You can simplify code by using false header nodes
class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy=new ListNode(0); dummy.next=head; ListNode fast=head; ListNode slow=dummy; while(n>0){ fast=fast.next; n--; } while(fast!=null){ fast=fast.next; slow=slow.next; } slow.next=slow.next.next; return dummy.next; } }
22 Swordfinger Offer II 022. Entry node of a ring in a chain table
Given a list of chains, returns the first node where the list of chains begins to ring. The first node that enters the ring along the next pointer from the head node of the chain list is the entry node of the ring. If the list of chains is not looped, null is returned.
Solution ideas: fast slow pointer
public class Solution { public ListNode detectCycle(ListNode head) { ListNode fast=head; ListNode slow=head; while(fast!=null&&fast.next!=null){ fast=fast.next.next; slow=slow.next; if(slow==fast){//Fast and slow pointers meet, indicating a ring fast=head; while(fast!=slow){//Let the fast pointer point to the head node, and then the fast and slow pointers move at the same time. The point where the fast pointer meets again is the entry point fast=fast.next; slow=slow.next; } return fast; } } return null; } }
Idea 2: Hash table, save visited nodes in Set, the first node to be duplicated is the ring entry point
23 Swordfinger Offer II 023.First coincident node of two linked lists
Given the header nodes headA and headB of two single-chain tables, find and return the starting node where the two single-chain tables intersect. Returns null if the two linked lists do not intersect.
Idea 1: Double Pointer
A pointer starts from headA, is empty, starts from headB
The other pointer starts from headB, is empty, and starts from headA
It's the same journey when we meet like this
It is important to note that if there is no intersection between the two lists, the second pass will exit the loop if both pointers point to null
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { ListNode tempA=headA; ListNode tempB=headB; while( tempA!=tempB){ tempA=(tempA!=null)?tempA.next:headB; tempB=(tempB!=null)?tempB.next:headA; } return tempA; } }
Idea 2: Hash table
Put a list of chains all into Set, then into the second list of nodes, the first duplicate is the intersection, no duplicate node returns Null
Idea three: Violence two-level while cycle, comparing each node of another list in one chain in turn
Day 8 list 2021.08.13
24 Swordfinger Offer II 024. Reverse Chain List
Idea 1: Iteration
class Solution { public ListNode reverseList(ListNode head) { ListNode pre=null; ListNode cur=head; ListNode next=null; while(cur!=null){ next=cur.next; cur.next=pre; pre=cur; cur=next; } return pre; } }
Iteration+Artificial Head
class Solution { public ListNode reverseList(ListNode head) { ListNode dummy=new ListNode(0); //dummy.next=head; ListNode temp=dummy; ListNode end=null; while(head!=null){ ListNode next=head.next; end=temp.next; temp.next=head; head.next=end; head=next; } return dummy.next; } }
Idea 3: Recursion
class Solution { public ListNode reverseList(ListNode head) { if(head==null||head.next==null) return head; ListNode p=reverseList(head.next); head.next.next=head; head.next=null; return p; } }
public ListNode reverseList(ListNode head) { // Last node, will become the head node in the end ListNode last = null; while(head!=null){ // Temporarily save next node ListNode next = head.next; // Next node points to previous node head.next = last; // Execute and record the current node last = head; // Next Node head = next; } return last; } Author: felix-he Links: https://leetcode-cn.com/problems/UHnkqh/solution/fan-zhuan-lian-biao-xiang-jie-ban-by-fel-tyu5/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
25 Swordfinger Offer II 025. Addition of Two Numbers in a Chain List
Given two non-empty linked lists l1 and l2 to represent two non-negative integers. The highest digits are at the beginning of the linked list. Each of their nodes stores only one digit. Adding the two numbers together returns a new linked list.
It can be assumed that neither number starts with zero except the number 0.
Solution ideas: first invert the two list of chains, and then become the second question two numbers added together, then add the inverted list of chains, and then invert the results you get
class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { l1= reverseList(l1); l2= reverseList(l2); ListNode node=addTwoNumbers(l1, l2,0); return reverseList(node); } public ListNode reverseList(ListNode head){ if(head==null||head.next==null) return head; ListNode p=reverseList(head.next); head.next.next=head; head.next=null; return p; } public ListNode addTwoNumbers(ListNode l1, ListNode l2,int a){ if(l1==null&&l2==null) return a==0?null:new ListNode(a);//The list goes to the end, but there is a carry case if(l1!=null){ a+=l1.val; l1=l1.next; } if(l2!=null){ a+=l2.val; l2=l2.next; } ListNode node=new ListNode(a%10); node.next=addTwoNumbers(l1, l2,a/10); return node; } }
Idea 2: Using stacks
The main difficulty of this topic is that the order of the digits in the list of chains is opposite to the order in which we add them. In order to process all digits in reverse order, we can use the stack: push all digits into the stack, and then take out the sum one by one. Carry-in situations need to be noted in the calculation.
class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { Deque<Integer> stack1 = new LinkedList<Integer>(); Deque<Integer> stack2 = new LinkedList<Integer>(); while (l1 != null) { stack1.push(l1.val); l1 = l1.next; } while (l2 != null) { stack2.push(l2.val); l2 = l2.next; } int carry = 0; ListNode ans = null; while (!stack1.isEmpty() || !stack2.isEmpty() || carry != 0) { int a = stack1.isEmpty() ? 0 : stack1.pop(); int b = stack2.isEmpty() ? 0 : stack2.pop(); int cur = a + b + carry; carry = cur / 10; cur %= 10; ListNode curnode = new ListNode(cur); curnode.next = ans; ans = curnode; } return ans; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/add-two-numbers-ii/solution/liang-shu-xiang-jia-ii-by-leetcode-solution/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
26 Swordfinger Offer II 026. Rearrangement list
Ideas: Using stack, putting all the chain list nodes on the stack, and then the next operation is equivalent to taking an element from the stack and inserting it into the chain table on the basis of the original chain table. Four elements need to pop up twice, seven elements need to pop up three times, and the number of popups is divided by the length of the chain table by two
class Solution { public void reorderList(ListNode head) { Stack<ListNode>stack=new Stack(); ListNode temp=head; int count=0; while(temp!=null){ stack.push(temp); temp=temp.next; count++; } temp=head; int mod=count/2;//Stack pops up to this many times while(mod>0){ ListNode next=temp.next; temp.next=stack.pop(); temp=temp.next; temp.next=next; temp=next; mod--; } temp.next=null; } }
Can merge again
2021.08.14 9th day list
27 Swordfinger Offer II 027. Palindrome Chain List
Given the head node of a chain table, determine if it is a palindrome chain table.
If a chain table is palindrome, then the chain list node sequence is the same from going backward to looking backward to looking forward.
Solution Idea 1: Store all the values of the node on the stack, and then start traversing from the beginning to see if each value is equal to the top of the stack
class Solution { public boolean isPalindrome(ListNode head) { Stack<Integer>stack=new Stack(); ListNode temp=head; while(temp!=null){ stack.push(temp.val); temp=temp.next; } temp=head; while(temp!=null){ if(temp.val!=stack.pop()) return false; temp=temp.next; } return true; } }
Idea 2: Find the intermediate node, reverse the second half of the list, and compare
It is important to note that if the length of the chain table is odd, the first part will be one more length than the second half.
If the length of the chain table is even, the length of the first and second half are equal
So during traversal, if the second half of the traversal is complete, the traversal stops
class Solution { public boolean isPalindrome(ListNode head) { //Solution Idea 2, find the intermediate node, reverse the latter half of the list if(head==null||head.next==null) return true; ListNode mid= finMid(head); ListNode reverse=reverseList(mid.next);//Head Node After Later Half Segment Inversion while(reverse!=null){ if(head.val!=reverse.val) return false; head=head.next; reverse=reverse.next; } return true; } public ListNode finMid(ListNode head){ ListNode fast=head.next; ListNode slow=head; if(head.next.next==null) { return slow; } while(fast!=null&&fast.next!=null){ fast=fast.next.next; slow=slow.next; } return slow; } public ListNode reverseList(ListNode head){ if(head==null||head.next==null) return head; ListNode p= reverseList(head.next); head.next.next=head; head.next=null; return p; } }
Above is to find the midpoint and then reverse, or to find the midpoint, while traversing, while reversing
class Solution { public boolean isPalindrome(ListNode head) { if(head == null || head.next == null) { return true; } ListNode slow = head, fast = head; ListNode pre = head, prepre = null; while(fast != null && fast.next != null) { pre = slow; slow = slow.next; fast = fast.next.next; pre.next = prepre; prepre = pre; } if(fast != null) { slow = slow.next; } while(pre != null && slow != null) { if(pre.val != slow.val) { return false; } pre = pre.next; slow = slow.next; } return true; } }
Idea 3 Put the element in the array and use the double pointer
class Solution { public boolean isPalindrome(ListNode head) { List<Integer> vals = new ArrayList<Integer>(); // Copy the values of the list of chains into the array ListNode currentNode = head; while (currentNode != null) { vals.add(currentNode.val); currentNode = currentNode.next; } // Use double pointer to determine palindrome int front = 0; int back = vals.size() - 1; while (front < back) { if (!vals.get(front).equals(vals.get(back))) { return false; } front++; back--; } return true; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/palindrome-linked-list/solution/hui-wen-lian-biao-by-leetcode-solution/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
Idea 4 Recursion
class Solution { private ListNode frontPointer; private boolean recursivelyCheck(ListNode currentNode) { if (currentNode != null) { if (!recursivelyCheck(currentNode.next)) { return false; } if (currentNode.val != frontPointer.val) { return false; } frontPointer = frontPointer.next; } return true; } public boolean isPalindrome(ListNode head) { frontPointer = head; return recursivelyCheck(head); } }
28 Swordfinger Offer II 028. Flattening Multilevel Two-way Chain List
In a multilevel two-way Chain table, in addition to pointers to the next and previous nodes, it also has a sublist pointer, which may point to a separate two-way Chain table. These sublists may also have one or more of their own subitems, and so on, to generate a multilevel data structure, as shown in the following example.
Given the head node at the first level of the list, flatten the list by flattening such a multilevel two-way list into a common two-way list so that all the nodes appear in a single-level double-chain list.
Idea 1 Recursion
class Solution { private Node node; public Node flatten(Node head) { if(head == null) { return null; } if(node != null) { node.next = head; head.prev = node; node.child = null; } node = head; //When you start traversing your child (e.g. 3, 7), the next is changed, so save it with nextNode Node nextNode = head.next; flatten(head.child); flatten(nextNode); return head; } }
iteration
class Solution { public Node flatten(Node head) { if (head == null) return head; Node pseudoHead = new Node(0, null, head, null); Node curr, prev = pseudoHead; Deque<Node> stack = new ArrayDeque<>(); stack.push(head); while (!stack.isEmpty()) { curr = stack.pop(); prev.next = curr; curr.prev = prev; if (curr.next != null) stack.push(curr.next); if (curr.child != null) { stack.push(curr.child); // don't forget to remove all child pointers. curr.child = null; } prev = curr; } // detach the pseudo node from the result pseudoHead.next.prev = null; return pseudoHead.next; } } Author: LeetCode Links: https://leetcode-cn.com/problems/flatten-a-multilevel-doubly-linked-list/solution/bian-ping-hua-duo-ji-shuang-xiang-lian-biao-by-lee/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
29 Swordfinger Offer II 029. Sorted Circular Chain List
class Solution { public Node insert(Node head, int insertVal) { if(head==null)//The original list is empty. Create a new list and form a ring according to the title { head = new Node(insertVal); head.next=head; return head; } Node cur = head,max=null;//max is used to handle cases where the insertion value is less than the current minimum and greater than the current maximum while(cur.next!=head) { //Find insertion points that are greater than or equal to the current value and less than or equal to the next value. if(cur.val<=insertVal&&cur.next.val>=insertVal) break; //By the way, find the tail in ascending order if(cur.val>cur.next.val) max=cur; cur=cur.next; } //The ascending end end end is not found after traversing, so it must be the previous Node of the head, which is now cur if(max==null) max=cur; //Successfully find an insertion point that is greater than or equal to the current value and less than or equal to the next value, then insert it if(cur.val<=insertVal&&cur.next.val>=insertVal) { var nn = new Node(insertVal,cur.next); cur.next=nn; } //If no insertion point is found, then whether it is greater than the maximum or smaller than the minimum, it is after the current maximum (and certainly before the current minimum) else { var nn = new Node(insertVal,max.next); max.next=nn; } return head; } }
2021.08.15 Day 10 Hash Table
30 Swordfinger Offer II 030. Insertion, deletion and random access are containers for O(1)
HashMap+ArrayList
To delete O(1) in an array, swap the end data to delete the data, and then delete the end data.
HashMa key stores element values, value stores index of elements
class RandomizedSet { // Solution 1 // HashMap + ArrayList private Random random; private Map<Integer, Integer> map; private List<Integer> list; /** Initialize your data structure here. */ public RandomizedSet() { random = new Random(); // Position of elements in a list in a map storage set map = new HashMap<>(); list = new ArrayList<>(); } /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ public boolean insert(int val) { if (map.containsKey(val)) { return false; } map.put(val, list.size()); list.add(val); return true; } /** Removes a value from the set. Returns true if the set contained the specified element. */ public boolean remove(int val) { if (!map.containsKey(val)) { return false; } int size = list.size(); int idx = map.get(val); // If the element to be removed is not the last item in the list, move the element of the last item to the location to be removed if (idx < size - 1) { int lastItem = list.get(size - 1); list.set(map.get(val), lastItem); map.put(lastItem, idx); } list.remove(size - 1); map.remove(val); return true; } /** Get a random element from the set. */ public int getRandom() { return list.get(random.nextInt(list.size())); } } /** * Your RandomizedSet object will be instantiated and called as such: * RandomizedSet obj = new RandomizedSet(); * boolean param_1 = obj.insert(val); * boolean param_2 = obj.remove(val); * int param_3 = obj.getRandom(); */
The main requirement of this topic is to achieve the complexity that all three operations are o(1). First, the complexity of insertion is o(1). Most data structures can achieve the complexity. The difficulty lies in random access and deletion. It's easy to think of hash tables for the time complexity of deletion, and random access is easy to think of arrays accessed with subscripts.
Reference resources:
Add Link Descriptionhttps://leetcode-cn.com/problems/FortPu/solution/java-ti-jie-by-cuncun-cun-cun-cun-gpx3/
public class RandomizedSet { private class Node{ Node pre; Node next; int val; public Node(Node pre, Node tail, int val) { this.pre = pre; this.next = tail; this.val = val; } public Node() { } public Node(int val) { this.val = val; } } Node head; Node tail; Map<Integer,Node> map; ArrayList<Node> list; public RandomizedSet() { head=new Node(); tail=new Node(); map=new HashMap<>(); list=new ArrayList<>(); head.next=tail; tail.pre=head; } /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ public boolean insert(int val) { if(map.containsKey(val)) return false; Node node=new Node(val); tail.pre.next=node; node.pre=tail.pre; node.next=tail; tail.pre=node; list.add(node); map.put(val,node); return true; } /** Removes a value from the set. Returns true if the set contained the specified element. */ public boolean remove(int val) { if (!map.containsKey(val)) return false; Node node=map.get(val); node.pre.next=node.next; node.next.pre=node.pre; map.remove(val); list.remove(node); return true; } /** Get a random element from the set. */ public int getRandom() { int index=(int)(Math.random()*list.size()); return list.get(index).val; } }
31 Swordfinger Offer II 031. Minimum recently used cache
This is the code I wrote myself
First, the infrastructure is to use HashMap and two-way chaining tables. HashMap inserts and finds elements very quickly, but not orderly. Two-way chaining tables insert and delete quickly and orderly, but locating elements to delete takes time, so combining them
With a two-way chain table and HashMap,HashMap's key stores the incoming key, and the Value store encapsulates the Node type of key and value
We define a function to delete nodes and a function to insert nodes in the chain header
Delete: Depending on the key passed in, go to hashMap to check if there is a corresponding Key. If not, go back to -1 directly. If there is, delete this node from its current location because it is a two-way Chain table, so delete element designs the pointer of the node before and after the current element changes to point to
Insert Head: You can use a false head, which is equivalent to inserting a node after the head node. It is very simple
class LRUCache { private int cap; private int count=0;//Count how many elements are currently stored private Map<Integer,Node>map=new HashMap(); Node head=null;//Record the header nodes of a two-way chain table Node tail=null;//Record the end of a two-way chain table public LRUCache(int capacity) { this.cap=capacity; } public int get(int key) { if(map.containsKey(key)){ Node node=map.get(key); delete(node.key); addToFirst(node);//Then add to the chain header return node.val; } return -1; } public void put(int key, int value) { Node node=new Node(key,value); if(map.containsKey(key)){ delete(key);//If there is a current key in the map, remove it first. addToFirst(node);//Then add to the chain header } else { if(count==cap){ delete(tail.key); addToFirst(node);//Then add to the chain header } else{ addToFirst(node);//Then add to the chain header } } } public void delete(int key){ Node node=map.get(key); if(node==head){//Is the first node if(head.next!=null){//There is not only one node head.next.pre=null; head=head.next; } else{//When there is only one node head=null; tail=null; } } else if(node==tail){//Is the last node if(tail.pre!=null)//There is not only one node tail.pre.next=null; tail=tail.pre;//Only one node will execute } else{ node.pre.next=node.next; node.next.pre=node.pre; } map.remove(key); count--; } public void addToFirst(Node node){ if(head==null)//There are currently no elements head=tail=node; else {//Current list has elements node.next=head; head.pre=node; head=node; } count++; map.put(node.key,node); } } class Node{ int key; int val; Node pre; Node next; public Node(int key,int val){ this.key=key; this.val=val; } } /** * Your LRUCache object will be instantiated and called as such: * LRUCache obj = new LRUCache(capacity); * int param_1 = obj.get(key); * obj.put(key,value); */
Seeing a solution is similar to what I think, but simpler than what I see
class ListNode { //Member variables int key; int value; ListNode next; ListNode prev; //Construction method public ListNode(int key, int value){ this.key = key; this.value = value; } } class LRUCache { //Member variables private ListNode head;//Virtual Header Node private ListNode tail;//Virtual Tail Node private Map<Integer, ListNode> numToNode;//The key of the hash table is the key of the cache private int capacity; public LRUCache(int capacity) { numToNode = new HashMap<>(); //Initialize Bi-directional Chain List head = new ListNode(-1, -1); tail = new ListNode(-1, -1); head.next = tail; tail.prev = head; this.capacity = capacity; } public int get(int key) { if(!numToNode.containsKey(key)){ return -1; } ListNode node = numToNode.get(key); moveToTail(node, node.value); return node.value; } public void put(int key, int value) { if(numToNode.containsKey(key)){//Hash table contains keys moveToTail(numToNode.get(key), value); }else{//Hash table does not contain keys if(numToNode.size() == capacity){//Cache reaches maximum capacity ListNode node = head.next; deleteNode(node);//Two-way list deletes the least recently used node numToNode.remove(node.key);//Hash Table (Cache) Deletes the least recently used node } //Cache did not reach capacity limit ListNode node = new ListNode(key, value); insertToTail(node);//Bidirectional Chain List Insert Node numToNode.put(key, node);//Hash Table (Cache) Insert Node } } //Move the node to the end of the two-way Chain List private void moveToTail(ListNode node, int newValue){ deleteNode(node); node.value = newValue;//If you insert a key-value pair, the keys are the same, the values are different, and you want to move the node value updates to the end of the two-way chain table insertToTail(node); } //Delete Node private void deleteNode(ListNode node){ node.prev.next = node.next; node.next.prev = node.prev; } //Inserts a node at the end of a two-way chain table private void insertToTail(ListNode node){ tail.prev.next = node; node.prev = tail.prev; node.next = tail; tail.prev = node; } }
class LRUCache { class Node { int k, v; Node l, r; Node(int _k, int _v) { k = _k; v = _v; } } int n; Node head, tail; Map<Integer, Node> map; public LRUCache(int capacity) { n = capacity; map = new HashMap<>(); head = new Node(-1, -1); tail = new Node(-1, -1); head.r = tail; tail.l = head; } public int get(int key) { if (map.containsKey(key)) { Node node = map.get(key); refresh(node); return node.v; } return -1; } public void put(int key, int value) { Node node = null; if (map.containsKey(key)) { node = map.get(key); node.v = value; } else { if (map.size() == n) { Node del = tail.l; map.remove(del.k); delete(del); } node = new Node(key, value); map.put(key, node); } refresh(node); } // The refresh operation is a two-step process: // 1. First remove the current node from the two-way list (if the node itself exists in the two-way list) // 2. Add the current node to the two-way Chain header void refresh(Node node) { delete(node); node.r = head.r; node.l = head; head.r.l = node; head.r = node; } // delete operation: remove the current node from the two-way chain table // Since we have pre-established two senders, head and tail, if node.l is not empty, it represents that the node itself exists in a two-way chain table (not a new node) void delete(Node node) { if (node.l != null) { Node left = node.l; left.r = node.r; node.r.l = left; } } }
This is an improved version of my own code, with a head-to-tail sentry and fewer head-to-end and end-to-end judgments
class LRUCache { private int cap; private int count=0;//Count how many elements are currently stored private Map<Integer,Node>map=new HashMap(); Node head=null;//Record the header nodes of a two-way chain table Node tail=null;//Record the end of a two-way chain table public LRUCache(int capacity) { this.cap=capacity; head=new Node(-1,-1); tail=new Node(-1,-1); head.next=tail; tail.pre=head; } public int get(int key) { if(!map.containsKey(key)) return -1; Node node=map.get(key); delete(node.key); addToFirst(node);//Then add to the chain header return node.val; } public void put(int key, int value) { Node node=new Node(key,value); if(map.containsKey(key)){ delete(key);//If there is a current key in the map, remove it first. addToFirst(node);//Then add to the chain header } else { if(count==cap) delete(tail.pre.key); addToFirst(node);//Then add to the chain header } } public void delete(int key){ Node node=map.get(key); node.pre.next=node.next; node.next.pre=node.pre; map.remove(key); count--; } public void addToFirst(Node node){ node.next=head.next; node.pre=head; head.next.pre=node; head.next=node; count++; map.put(node.key,node); } } class Node{ int key; int val; Node pre; Node next; public Node(int key,int val){ this.key=key; this.val=val; } }
Implement with LinkedHashMap
class LRUCache { int cap; LinkedHashMap<Integer,Integer> cache=new LinkedHashMap<>(); public LRUCache(int capacity) { this.cap = capacity; } public int get(int key) { if(!cache.containsKey(key)) return -1; // Change key to most recently used makeRecently(key); return cache.get(key); } public void put(int key, int value) { if (cache.containsKey(key)) { cache.put(key, value);// Modify the value of key makeRecently(key); // Change key to most recently used return; } if (cache.size() >= this.cap) { // The chain header is the oldest unused key int oldestKey = cache.keySet().iterator().next(); cache.remove(oldestKey); } cache.put(key, value); // Add a new key to the end of the list } private void makeRecently(int key) { int val= cache.get(key); cache.remove(key); // Remove the key and reinsert it at the end of the queue cache.put(key,val); } }
32 Swordfinger Offer II 032. Valid Variants
Given two strings s and t, write a function to determine if they are a set of anaglyphs (heterographic words).
Note: s and T are mutually anaglyphs (ectopic letters) if each character in s and t occurs the same number of times and in a different character order.
First the question can be judged by sorting
Solution ideas: Compare the number of occurrences of each character in two strings, and store them in an array. The character of the first string adds 1 to the corresponding value in the array, the character of the second string subtracts 1 from the corresponding value in the array, and the value in the last array should all be 0. If not, return false
class Solution { public boolean isAnagram(String s, String t) { int n1=s.length(); int n2=t.length(); if(n1!=n2) return false; if(s.equals(t)) return false; int arr[]=new int [128]; for(int i=0;i<n1;i++) arr[s.charAt(i)-32]++; for(int i=0;i<n2;i++){ arr[t.charAt(i)-32]--; if(arr[t.charAt(i)-32]<0) return false; } for(int i=0;i<128;i++){ if(arr[i]%2!=0) return false; } return true; } }
The Title requires Unicode characters to be processed, so we can consider using a hash table to process them
For advanced problems, Unicode is a solution to the limitations of traditional character encoding, which specifies a unique binary encoding for characters in each language. Unicode may have a character corresponding to more than one byte. In order to let the computer know how many bytes represent a character, the transmission-oriented encoding methods UTF_8 and UTF_16 were gradually used. Specifically relevant knowledge readers can continue to read relevant information to expand their horizons, which will not be expanded here.
Back to this point, the core point of the advanced problem is "Characters are discrete and unknown", so we can just maintain the frequency of corresponding characters with a hash table. At the same time, the reader needs to be aware that Unicode may correspond to more than one byte of a character, and different languages handle string reading differently.
class Solution { public boolean isAnagram(String s, String t) { if (s.length() != t.length()) { return false; } if(s.equals(t)) return false; Map<Character, Integer> table = new HashMap<Character, Integer>(); for (int i = 0; i < s.length(); i++) { char ch = s.charAt(i); table.put(ch, table.getOrDefault(ch, 0) + 1); } for (int i = 0; i < t.length(); i++) { char ch = t.charAt(i); table.put(ch, table.getOrDefault(ch, 0) - 1); if (table.get(ch) < 0) { return false; } } return true; } }
2021.08.16 11 Hash Table
33 Swordfinger Offer II 033. Degeneric Phrases
Solving ideas:
Two strings are heterographic words for each other if and only if they contain the same letter. Strings in the same set of hetero-alphabetic words have the same points. You can use the same points as the flags for a set of hetero-alphabetic words, use a hash table to store each set of hetero-alphabetic words, use the hash table keys as the flags for a set of hetero-alphabetic words, and use the hash table values as a list of hetero-alphabetic words.
Traverse through each string, and for each string, get the flags of the set of alphabetic words in which the string is located, and add the current string to the list of alphabetic words in that set. After traversing all strings, each key-value pair in the hash table is a set of alphabetic words.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String,List<String>>map=new HashMap(); List<List<String>> list; for(String s:strs){ char[]arr=s.toCharArray(); Arrays.sort(arr); String temp=new String(arr); if(map.containsKey(temp)){ map.get(temp).add(s); }else{ map.put(temp,new ArrayList()); map.get(temp).add(s); } } return new ArrayList<List<String>>(map.values()); } }
Idea 2: Count
That's great. Count the number of occurrences of each letter, stitch letters and occurrences together into a string as the key value of HashMap. That's great. Value is also a chain table. As long as it's a meta phrase, the strings stitched in alphabetical order and number of occurrences must be equal.
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> map = new HashMap<String, List<String>>(); for (String str : strs) { int[] counts = new int[26]; int length = str.length(); for (int i = 0; i < length; i++) { counts[str.charAt(i) - 'a']++; } // Each occurrence greater than 0 letters and occurrences are concatenated sequentially into strings as keys to the hash table StringBuffer sb = new StringBuffer(); for (int i = 0; i < 26; i++) { if (counts[i] != 0) { sb.append((char) ('a' + i)); sb.append(counts[i]); } } String key = sb.toString(); List<String> list = map.getOrDefault(key, new ArrayList<String>()); list.add(str); map.put(key, list); } return new ArrayList<List<String>>(map.values()); } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/group-anagrams/solution/zi-mu-yi-wei-ci-fen-zu-by-leetcode-solut-gyoc/ Source: Force buckle ( LeetCode) Copyright belongs to the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
(To be) 34 Swordfinger Offer II 034. Ordering of Alien Languages
35 Swordfinger Offer II 035. Minimum time difference
Given a 24-hour time list (hour: minute "HH:MM"), find the minimum time difference between any two times in the list and express it in minutes.
Example 1:
Input: timePoints = ['23:59','00:00']
Output: 1
Example 2:
Input: timePoints = ['00:00','23:59','00:00']
Output: 0
Solve the problem by first converting all the time into an integer value of the number of minutes, up to 24 * 60 = 1440 minutes a day, so if the length of the list exceeds 1440, return directly to 0
After the number of minutes has been calculated, sort, and then calculate the difference between adjacent elements in turn. To get the minimum value, you also need to take the time difference between the minimum value and the maximum value, such as the time difference between 23:59 and 00:01, to compare with the minimum value
Reference resources: https://leetcode-cn.com/problems/minimum-time-difference/solution/gao-xiao-jie-jue-wen-ti-by-leecode-vh-d6yo/
class Solution { private int parseMinute(String str) { return str.charAt(0) * 600 + str.charAt(1) * 60 + str.charAt(3) * 10 +str.charAt(4); } public int findMinDifference(List<String> timePoints) { int len = timePoints.size(); if (len < 2 || len > 1440) { return 0; } int[] times = new int[len]; for(int i = 0; i < len; i++) { times[i] = parseMinute(timePoints.get(i)); } Arrays.sort(times); int min = Integer.MAX_VALUE; for(int i = 0; i < len - 1; i++) { min = Math.min(min, times[i+1] - times[i]); if (min == 0) return 0; } return Math.min(min, 1440 - times[len-1] + times[0]); } }
2021.08.17 12th Day Stack
36 Swordfinger Offer II 036. Suffix expression
Solve the problem by pushing the stack when it encounters an operand, taking out two operands when it encounters an operator, and making the first operand from the later extracted elements
class Solution { public int evalRPN(String[] tokens) { Stack<Integer>stack=new Stack(); int a=0;int b=0; for(int i=0;i<tokens.length;i++){ String s =tokens[i]; switch(s){ case "+": a=stack.pop(); b=stack.pop(); stack.push(a+b); break; case "-": a=stack.pop(); b=stack.pop(); stack.push(b-a); break; case "*": a=stack.pop(); b=stack.pop(); stack.push(b*a); break; case "/": a=stack.pop(); b=stack.pop(); stack.push(b/a); break; default: stack.push(Integer.valueOf(s)); } } return stack.pop(); } }
Learn, not so many popups
class Solution { public int evalRPN(String[] tokens) { Deque<Integer> stack = new LinkedList<Integer>(); int n = tokens.length; for (int i = 0; i < n; i++) { String token = tokens[i]; if (isNumber(token)) { stack.push(Integer.parseInt(token)); } else { int num2 = stack.pop(); int num1 = stack.pop(); switch (token) { case "+": stack.push(num1 + num2); break; case "-": stack.push(num1 - num2); break; case "*": stack.push(num1 * num2); break; case "/": stack.push(num1 / num2); break; default: } } } return stack.pop(); } public boolean isNumber(String token) { return !("+".equals(token) || "-".equals(token) || "*".equals(token) || "/".equals(token)); } }
Bye 100% of the code
class Solution { public int evalRPN(String[] tokens) { int[] stack = new int[tokens.length]; int top = -1; for (String token : tokens) { switch (token) { case "+": stack[top - 1] += stack[top]; top--; break; case "-": stack[top - 1] -= stack[top]; top--; break; case "*": stack[top - 1] *= stack[top]; top--; break; case "/": stack[top - 1] /= stack[top]; top--; break; default: stack[++top] = Integer.valueOf(token); } } return stack[top]; } }
37 Swordfinger Offer II 037. Asteroid collisions
The solution, it's all in the code
Positive numbers on the stack, such as negative numbers to touch, always compare the top of the stack, the top of the stack is positive, and the current non-negative number and the top of the stack add up less than 0, pop up the top of the stack, cycle comparison
When the above step no longer pops up, either the stack is empty or the top of the stack is already negative, so we directly stack the current negative number
Or it could be that the current element and the top of the stack add up to zero and pop up the top of the stack directly
class Solution { public int[] asteroidCollision(int[] nums) { int n=nums.length; int i=0; //Mark planets less than 0 on the left, i planets less than 0 on the left Stack<Integer>stack=new Stack(); while(i<=n-1&&nums[i]<0){ stack.push(nums[i]);//Add all the negative numbers at the beginning to the stack because they don't collide i++; } for(int cur=i;cur<n;cur++){ if(nums[cur]>0)//Direct stacking of positive numbers stack.push(nums[cur]); else{ //negative while(!stack.isEmpty()&&stack.peek()>0&&nums[cur]+stack.peek()<0){//If the sum is less than 0 and the top of the stack is a positive number, the top element always pops up stack.pop(); } if(stack.isEmpty()||(!stack.isEmpty()&&stack.peek()<0)){//Empty stack or negative number at top, stacked stack.push(nums[cur]); } else {//Stack is not empty, nor is the top of the stack a negative number if(stack.peek()>0&&nums[cur]+stack.peek()==0){//Add equals 0, pop up top of stack stack.pop(); } } } } int size=stack.size(); int arr[]=new int[size]; for(int k=size-1;k>=0;k--){ arr[k]=stack.pop(); } return arr; } }
Look at people's code. It's so elegant
class Solution { public int[] asteroidCollision(int[] asteroids) { int[] stack = new int[asteroids.length]; int top = -1; for(int a:asteroids){ while(a<0&&top>=0&&stack[top]>0&&stack[top]<-a){ top--; } if(a<0&&top>=0&&stack[top]>=-a){ if(stack[top]==-a) top--; continue;//The current negative number is canceled out and does not go on the stack } stack[++top] = a; } int[] res = new int[top+1]; for(int i = 0;i<=top;i++) res[i] = stack[i];//This is because the ++ top operation results in the last additional element return res; } }
38 Swordfinger Offer II 038. Daily temperature
Please regenerate a list based on the daily temperature list temperatures and ask the output of its corresponding location to be: At least the number of days to wait to see higher temperatures. If the temperature will not rise after that, replace it with 0 at that location.
Solution ideas: use monotonic stack, arrays there, put the last higher number that is not currently matched on the stack, match to the current array element is larger than the top of the stack, then the corresponding number of days to wait for the top element of the stack is the index of the current array element minus the index of the top element of the stack
How do I find the index of the top element of the stack?
I encapsulate the data and index of each element into a node on the stack, which makes it easy to get the index of that element.
It can also be stored in a one-dimensional array
Finally, when the array is traversed, the number of days to wait for the remaining elements in the stack is zero
class Solution { public int[] dailyTemperatures(int[] nums) { //Using a monotonic stack, but how do I match the index, I encapsulate the index and data into a node and add it to the stack? Stack<Node>stack=new Stack(); stack.push(new Node(nums[0],0)); for(int i=1;i<nums.length;i++){ while(!stack.isEmpty()&&nums[i]>stack.peek().val){ int index=stack.pop().index; nums[index]=i-index; } stack.push(new Node(nums[i],i)); } //Finally, when the array is traversed, the number of days to wait for the remaining elements in the stack is zero while(!stack.isEmpty()){ nums[stack.pop().index]=0; } return nums; } } class Node{ int val; int index; Node(int val,int index){ this.val=val; this.index=index; } }
Am I an hanpi? I save the index when I put it on the stack........
class Solution { public int[] dailyTemperatures(int[] nums) { //Using a monotonic stack, but how do I match the index, I encapsulate the index and data into a node and add it to the stack? Stack<Integer>stack=new Stack(); stack.push(0); for(int i=1;i<nums.length;i++){ while(!stack.isEmpty()&&nums[i]>nums[stack.peek()]){ int index=stack.pop(); nums[index]=i-index; } stack.push(i); } //Finally, when the array is traversed, the number of days to wait for the remaining elements in the stack is zero while(!stack.isEmpty()){ nums[stack.pop()]=0; } return nums; } }
Idea 2: Dynamic planning
If the current nums[i] is smaller than nums[j], the corresponding j-i is obtained directly, otherwise it is adjusted to the larger number than nums[j]. This is j=j += res[j],res[j] is 0, indicating that there is no greater number behind nums[j]
Come on a quick one
Sequential traversal does not actually make the most efficient use of previous calculations or is a find (reverse order is as simple as predicting the future, so jumping directly is fine)
Reference resources: https://leetcode-cn.com/problems/daily-temperatures/solution/dpde-si-wei-by-ryaninnerpeace-9ib3/
class Solution { public int[] dailyTemperatures(int[] temperatures) { int[] res = new int[temperatures.length]; res[temperatures.length - 1] = 0; for (int i = temperatures.length - 2; i >= 0; i--) { for (int j = i + 1; j < temperatures.length; j += res[j]) { if (temperatures[i] < temperatures[j]) { res[i] = j - i; break; } else if (res[j] == 0) { res[i] = 0; break; } } } return res; } }
2021.08.18 Day 13 Stack
39 Swordfinger Offer II 039. Maximum rectangular area of histogram
Solution Idea 1: Enumeration of Violence
The area of the largest histogram that can be exported must be the height of a column. We can find the maximum by using the height of each column as the maximum histogram.
class Solution { public int largestRectangleArea(int[] nums) { int n=nums.length; Stack<Node>stack=new Stack(); stack.push(new Node(-1,0));//First put the first element on the stack int max=0; //The general idea is to enumerate the height of each column as a rectangle, find the area of each rectangle, and then go to the maximum value //To find the area, you also need to know the width, which is the distance between the first element smaller than the current column and the next one smaller than it. for(int i=1;i<n;i++){ if(!stack.isEmpty()&&nums[i]<nums[stack.peek().index]){ while(!stack.isEmpty()&&nums[i]<nums[stack.peek().index]){//Possibly the next smaller element of the preceding elements Node node=stack.pop(); int tempArea=nums[node.index]*(i-node.smallerIndex-1);//We calculated the area of a rectangle that is higher than the current nums[i] max=Math.max(max,tempArea); } if(stack.isEmpty()){//The stack is empty, indicating that the current point is too small, eliminating all the previous ones, the previous smaller element index is -1 stack.push(new Node(-1,i)); }else{ int smallerIndex= (nums[i]==nums[stack.peek().index])?stack.peek().smallerIndex:stack.peek().index; stack.push(new Node(smallerIndex,i));//How do I find this smallerIndex? When the end of the while, the stack is not empty, and the current element is either greater than or equal to the top of the stack, so the two-minute case above } } else if(!stack.isEmpty()&&nums[i]>nums[stack.peek().index]){ stack.push(new Node(stack.peek().index,i));//If it is greater than the current top of the stack, then the current top of the stack is the previous number smaller than it } else if(!stack.isEmpty()&&nums[i]==nums[stack.peek().index]){//If equal to the top of the stack, their previous smaller element is equal stack.push(new Node(stack.peek().smallerIndex,i)); } } while(!stack.isEmpty()){ //If the stack is not empty, then there are no smaller elements left behind. We need to know that the top of the remaining stack must be the last element of the original array, because no one can eliminate it //So the rest of the stack goes to the end Node node=stack.pop(); int tempArea=nums[node.index]*(n-node.smallerIndex-1); max=Math.max(max,tempArea); } return max; } //Consider encapsulating the current index and the index of the first element smaller than it into a node class Node{ int smallerIndex; int index; Node(int smallerIndex,int index){ this.smallerIndex=smallerIndex; this.index=index; } } }
Array simulation stack, too elegant
class Solution { public int largestRectangleArea(int[] heights) { int n = heights.length; int[] stack = new int[n]; int top = -1; int res = 0; for(int i = 0;i<n;i++){ while(top>=0&&heights[stack[top]]>heights[i]){ int r = i; int l = top>=1?stack[top-1]+1:0; res = Math.max(res,(r-l)*heights[stack[top]]); top--; } stack[++top] = i; } while(top>=0){ int r = n; int l = top>=1?stack[top-1]+1:0; res = Math.max(res,(r-l)*heights[stack[top]]); top--; } return res; } }
40 Swordfinger Offer II 040.Largest Rectangle in Matrix
2021.08.19 Day 14 Pairing
41 Swordfinger Offer II 041. Average value of sliding window
Solution ideas: Initialize the container capacity size, and when the number of elements in the queue exceeds the specified container capacity, pop up the queue head element
class MovingAverage { /** Initialize your data structure here. */ int size; Queue<Integer>queue=new LinkedList(); double curSum=0.0; public MovingAverage(int size) { this.size=size; } public double next(int val) { queue.add(val); curSum+=val; if(queue.size()>size){ curSum-=queue.poll(); } return (double)curSum/(double)queue.size(); } }
42 Swordfinger Offer II 042. Recent requests
class RecentCounter { Queue<Integer>queue=new LinkedList(); public RecentCounter() { } public int ping(int t) { queue.offer(t); while(queue.peek()+3000<t){ queue.poll(); } return queue.size(); } }
43 Swordfinger Offer II 043. Add Nodes to Full Binary Tree
Solving ideas:
class CBTInserter { TreeNode root; Deque<TreeNode> deque; public CBTInserter(TreeNode root) { this.root = root; deque = new LinkedList(); Queue<TreeNode> queue = new LinkedList(); queue.offer(root); // BFS to populate deque while (!queue.isEmpty()) { TreeNode node = queue.poll(); if (node.left == null || node.right == null) deque.offerLast(node); if (node.left != null) queue.offer(node.left); if (node.right != null) queue.offer(node.right); } } public int insert(int v) { TreeNode node = deque.peekFirst(); deque.offerLast(new TreeNode(v)); if (node.left == null) node.left = deque.peekLast(); else { node.right = deque.peekLast(); deque.pollFirst(); } return node.val; } public TreeNode get_root() { return root; } }
2021.08.2015th Day Queue
44 Swordfinger Offer II 044.Maximum per layer of a binary tree
Solution ideas: traverse through the layers, record the maximum value of each layer, write it here first, if I can use dfs for this question, calculate it
class Solution { public List<Integer> largestValues(TreeNode root) { List<Integer>list=new ArrayList(); Queue<TreeNode>queue=new LinkedList(); if(root==null) return list; queue.offer(root); while(!queue.isEmpty()){ int size=queue.size(); int tempMax=0; for(int i=0;i<size;i++){ TreeNode temp=queue.poll(); if(i==0) tempMax=temp.val; else{ tempMax=Math.max(tempMax,temp.val); } if(temp.left!=null) queue.offer(temp.left); if(temp.right!=null) queue.offer(temp.right); } list.add(tempMax); } return list; } }
class Solution { public List<Integer> largestValues(TreeNode root) { //queue Queue<TreeNode> queue = new LinkedList<>(); List<Integer> res = new ArrayList<>(); if(root != null){ queue.add(root); } while(!queue.isEmpty()){ int max = Integer.MIN_VALUE; int levelSize = queue.size(); for(int i = 0; i < levelSize; i++){ TreeNode node = queue.poll(); max = Math.max(max, node.val); if(node.left != null){ queue.add(node.left); } if(node.right != null){ queue.add(node.right); } } res.add(max); } return res; } }
Idea 2: Deep-first search
That's too strong. If you traverse to the current depth and the list doesn't keep up with the size, you can put the current node's value in the list directly. Otherwise, you can compare the current value with the value that has been sent for the corresponding position in the list. That is, we want to make sure that the size of the list is the same as the maximum depth of the binary tree.
class Solution { ArrayList<Integer> res = new ArrayList<>(); public List<Integer> largestValues(TreeNode root) { dfs(root,0); return res; } public void dfs(TreeNode root , int d){ if(root == null){ return; } if(d == res.size()){ res.add(root.val); }else if(root.val > res.get(d)){ res.set(d,root.val); } dfs(root.left , d+1); dfs(root.right , d+1); } }
45 Swordfinger Offer II 045.The lowest leftmost value of a binary tree
Solution ideas 1: Width first search, temporarily save the first node out of the queue before each layer leaves the queue, until the queue is empty, directly return to the last temporary node value is OK
class Solution { public int findBottomLeftValue(TreeNode root) { List<Integer>list=new ArrayList(); Queue<TreeNode>queue=new LinkedList(); int result=0; queue.offer(root); while(!queue.isEmpty()){ int size=queue.size(); for(int i=0;i<size;i++){ TreeNode temp=queue.poll(); if(temp.left!=null) queue.offer(temp.left); if(temp.right!=null) queue.offer(temp.right); if(i==0){ result=temp.val; } } } return result; } }
Is this sequential traversal not clearer and more concise? Direct reverse, the last node that pops up the barrier is the leftmost node on the last layer
class Solution { public int findBottomLeftValue(TreeNode root) { if (root.left == null && root.right == null) { return root.val; } Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); TreeNode temp = new TreeNode(-100); while (!queue.isEmpty()) { temp = queue.poll(); if (temp.right != null) { // Add the right node to the queue first queue.offer(temp.right); } if (temp.left != null) { // Add the left node to the queue queue.offer(temp.left); } } return temp.val; } }
Idea 2, Depth first, the line finds the maximum depth of the binary tree and finds the first node whose depth equals the maximum depth.
My code is correct only if there is only one node in the last layer, otherwise the last node will be found
class Solution { int result=0; public int findBottomLeftValue(TreeNode root) { int maxDepth=GetMaxDepth(root); helper (root,1,maxDepth); return result; } public int GetMaxDepth(TreeNode root){ if(root==null) return 0; return 1+Math.max( GetMaxDepth(root.left), GetMaxDepth(root.right)); } public void helper (TreeNode root,int depth,int maxDepth){ if(root==null) return ; if( depth==maxDepth){ result=root.val; return ; } helper (root.left,depth+1,maxDepth); helper (root.right,depth+1,maxDepth); } }
Look at someone else's code again
class Solution { int maxHeight = -1; int left = 0; public int findBottomLeftValue(TreeNode root) { dfs(root, 0); return left; } void dfs(TreeNode root,int height) { if(root.left == null && root.right == null) { if(height > maxHeight) { maxHeight = height; left = root.val; } return; } if(root.left != null) dfs(root.left, height + 1); if(root.right != null) dfs(root.right, height + 1); } }
46 Swordfinger Offer II 046.Right view of binary tree
Solution Idea 1: Width first search, each time take the last node of each layer into the list
class Solution { public List<Integer> rightSideView(TreeNode root) { //Solving ideas, take the rightmost node of each layer List<Integer>list=new ArrayList(); Queue<TreeNode>queue=new LinkedList(); if(root==null) return list; queue.offer(root); while(!queue.isEmpty()){ int size=queue.size(); for(int i=0;i<size;i++){ TreeNode temp=queue.poll(); if(temp.left!=null) queue.offer(temp.left); if(temp.right!=null) queue.offer(temp.right); if(i==size-1){ list.add(temp.val); } } } return list; } }
Solving Ideas 2: Deep-first search
We do a deep-first search of the tree, and always access the right subtree first during the search. So for each layer, the first node we see in this layer must be the rightmost node.
We can store the first node at each depth of access, and once we know the number of layers of the tree, we get the final result array
class Solution { List<Integer> res=new ArrayList<>(); public List<Integer> rightSideView(TreeNode root) { dfs(root,0); return res; } public void dfs(TreeNode root,int depth){ if(root==null) return ; if(depth==res.size()){ res.add(root.val); } dfs(root.right,depth+1); dfs(root.left,depth+1); } }
Solving Idea 3: Using Stack
Put the left node on the stack, the right node on the stack, and then the right subtree will be traversed first
class Solution { public List<Integer> rightSideView(TreeNode root) { Map<Integer, Integer> rightmostValueAtDepth = new HashMap<Integer, Integer>(); int max_depth = -1; Stack<TreeNode> nodeStack = new Stack<TreeNode>(); Stack<Integer> depthStack = new Stack<Integer>(); nodeStack.push(root); depthStack.push(0); while (!nodeStack.isEmpty()) { TreeNode node = nodeStack.pop(); int depth = depthStack.pop(); if (node != null) { // Maintain the maximum depth of a binary tree max_depth = Math.max(max_depth, depth); // If no node of corresponding depth exists, we will insert it if (!rightmostValueAtDepth.containsKey(depth)) { rightmostValueAtDepth.put(depth, node.val); } nodeStack.push(node.left); nodeStack.push(node.right); depthStack.push(depth + 1); depthStack.push(depth + 1); } } List<Integer> rightView = new ArrayList<Integer>(); for (int depth = 0; depth <= max_depth; depth++) { rightView.add(rightmostValueAtDepth.get(depth)); } return rightView; } }
Day 16 Tree 2021.08.21
49 Swordfinger Offer II 049. Sum of path numbers from root node to leaf node
Solve the problem by recursively traversing, finding the leaf node, splicing the current string onto the leaf node, then adding it to the List, and finally converting the string in the list to an integer sum
class Solution { List<String>list=new ArrayList(); public int sumNumbers(TreeNode root) { helper( root,""); int result=0; for(int i=0;i<list.size();i++){ result+=Integer.valueOf(list.get(i)); } return result; } public void helper(TreeNode root,String s){ if(root==null){ return ; } if(root.left==null&&root.right==null){ list.add(s+root.val); } helper( root.left,s+root.val); helper( root.right,s+root.val); } }
Optimize, recursively with integers directly
class Solution { List<Integer>list=new ArrayList(); public int sumNumbers(TreeNode root) { helper( root,0); int result=0; for(int i=0;i<list.size();i++){ result+=list.get(i); } return result; } public void helper(TreeNode root,int s){ if(root==null){ return ; } if(root.left==null&&root.right==null){ list.add(s*10+root.val); } helper( root.left,s*10+root.val); helper( root.right,s*10+root.val); } }
Do not use list
class Solution { public int sumNumbers(TreeNode root) { return dfs(root, 0); } public int dfs(TreeNode root, int prevSum) { if (root == null) { return 0; } int sum = prevSum * 10 + root.val; if (root.left == null && root.right == null) { return sum; } else { return dfs(root.left, sum) + dfs(root.right, sum); } } }
breadth-first search
class Solution { public int sumNumbers(TreeNode root) { if (root == null) { return 0; } int sum = 0; Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>(); Queue<Integer> numQueue = new LinkedList<Integer>(); nodeQueue.offer(root); numQueue.offer(root.val); while (!nodeQueue.isEmpty()) { TreeNode node = nodeQueue.poll(); int num = numQueue.poll(); TreeNode left = node.left, right = node.right; if (left == null && right == null) { sum += num; } else { if (left != null) { nodeQueue.offer(left); numQueue.offer(num * 10 + left.val); } if (right != null) { nodeQueue.offer(right); numQueue.offer(num * 10 + right.val); } } } return sum; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/solution/qiu-gen-dao-xie-zi-jie-dian-shu-zi-zhi-he-by-leetc/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
2021.08.22 17th Day Tree
50 Swordfinger Offer II 050.Sum of Downward Path Nodes
Solution ideas: use prefix sum, calculate to the current node, check whether there is a prefix before and curSum-target
Reference resources: Prefix and, Recursive, Backward
class Solution { int result; Map<Integer,Integer>map=new HashMap(); public int pathSum(TreeNode root, int targetSum) { if(root==null) return 0; map.put(0,1); //Don't forget, or you'll undercount helper(root,targetSum,0); return result; } public void helper(TreeNode root,int targetSum,int curSum){ if(root==null) return ; curSum+=root.val; result+=map.getOrDefault(curSum-targetSum,0);//Note that you cannot change the position of the following sentence, otherwise [1], 0 would not work map.put(curSum,map.getOrDefault(curSum,0)+1); helper(root.left, targetSum, curSum); helper(root.right, targetSum, curSum); map.put(curSum,map.get(curSum)-1); } }
52 Swordfinger Offer II 052. Flattening a Binary Search Tree
Solution Idea 1: Traverse through all the nodes in a middle order (recursion, iteration), put them in a list, and then take them out in turn
Solution Idea 2: Recursively, create a false header node, in the middle of the traversal process, continuously add the traversed nodes behind the false header
class Solution { TreeNode head = new TreeNode(-1); TreeNode pre = head; public TreeNode increasingBST(TreeNode root) { inorder(root); return head.right; } public void inorder(TreeNode node) { if (node == null) { return; } inorder(node.left); pre.right = node; pre = node; pre.left = null; inorder(node.right); } }
2021.08.23 Day 18 Tree
2021.08.24 19th Day Tree
56 Swordfinger Offer II 056.Sum of two nodes in a binary search tree
Given the root node root and an integer k of a binary search tree, determine if there are two nodes in the binary search tree whose values sum to equal K. Assume that the values of the nodes in the binary search tree are unique.
Example 1:
Input: root = [8,6,10,5,7,9,11], k = 12
Output: true
Interpretation: The sum of Node 5 and Node 7 equals 12
Example 2:
Input: root = [8,6,10,5,7,9,11], k = 22
Output: false
Interpretation: There is no node with a sum of two node values of 22
Solve the problem by traversing in middle order and saving the traversed node values with set
class Solution { Set<Integer>set=new HashSet(); public boolean findTarget(TreeNode root, int k) { if(root==null){ return false; } if(set.contains(k-root.val)){ return true; } set.add(root.val); return findTarget( root.left, k)||findTarget( root.right, k); } }
57 Swordfinger Offer II 057. The difference between value and subscript is within a given range
Give you an array of integers nums and two integers k and t. Determine if there are two different subscripts I and j so that ABS (nums[i] - nums[j]) <= t satisfies ABS (i - j) <= k.
Returns true if it exists, false if it does not exist.
Example 1:
Input: nums = [1,2,3,1], k = 3, t = 0
Output:true
Example 2:
Input: nums = [1,0,1,1], k = 1, t = 2
Output:true
Example 3:
Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false
Solution Idea 1: Violence, Can't Solve
class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { int n=nums.length; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ long a=Math.abs((long)nums[i] - (long)nums[j]); if((a <= t)&& Math.abs(i - j) <= k) return true; } } return false; } }
Solving Ideas 2: Reference Gongshui Trifoliate: A Double Solution: "Sliding Window & Bisection" & "Bucket Sorting" Solution
class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { int n = nums.length; TreeSet<Long> ts = new TreeSet<>(); for (int i = 0; i < n; i++) { Long u = nums[i] * 1L; // Find the maximum value less than or equal to u from ts (the number nearest to u less than or equal to u) Long l = ts.floor(u); // Find the minimum value greater than or equal to u from ts (the number nearest to u greater than or equal to u) Long r = ts.ceiling(u); if(l != null && u - l <= t) return true; if(r != null && r - u <= t) return true; // Add the current number to ts and remove the number whose subscript range is not [max (0, I - k), i] (keep the sliding window size k) ts.add(u); if (i >= k) ts.remove(nums[i - k] * 1L); } return false; } }
class Solution { public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) { int len = nums.length; int[][] data = new int[len][2]; for (int i = 0; i < len; i++) data[i] = new int[]{nums[i], i}; Arrays.sort(data, Comparator.comparingInt(a -> a[0])); // Sort element values in ascending order for (int i = 0; i < len - 1; i++) { // Fixed the first number for (int j = i + 1; j < len; j++) { if ((long) data[j][0] - data[i][0] > t) break; if (Math.abs(data[j][1] - data[i][1]) <= k) return true; } } return false; } }
2021.08.25 20th heap
59 Swordfinger Offer II 059. Largest K Value of Data Flow
Design a class that finds the kth largest element in the data flow. Note that the kth largest element is sorted, not the kth different element.
Implement the KthLargest class:
KthLargest(int k, int[] nums) Use integers k And integer flow nums Initialize the object. int add(int val) take val Insert Data Stream nums After that, return to the k Large elements.
Example:
Input:
["KthLargest", "add", "add", "add", "add", "add"]
[[3, [4, 5, 8, 2]], [3], [5], [10], [9], [4]]
Output:
[null, 4, 5, 5, 8, 8]
Explanation:
KthLargest kthLargest = new KthLargest(3, [4, 5, 8, 2]);
kthLargest.add(3); // return 4
kthLargest.add(5); // return 5
kthLargest.add(10); // return 5
kthLargest.add(9); // return 8
kthLargest.add(4); // return 8
Source: LeetCode
Links: https://leetcode-cn.com/problems/jBjn9C
Copyright belongs to the withholding network. For commercial reprinting, please contact the official authorization. For non-commercial reprinting, please indicate the source.
Having written for half a day, it would be better to have a priority queue.
class KthLargest { int nums[]; int k; int max=Integer.MIN_VALUE; public KthLargest(int a, int[] arr) { nums=new int[k]; for(int i=0;i<k;i++){ nums[i]=arr[i]; } k=a; buildHeap(nums,k); for(int i=k;i<nums.length;i++){ if(nums[i]>nums[0]){ swap(nums,0,i); heaplify( nums,0,k); } } } public int add(int val) { if(nums.length<k){ return Math.max(max,val); } if(val>nums[0]){ nums[0]=val; heaplify(nums,0,k); } return nums[0]; } public void buildHeap(int nums[],int k){ for(int i=nums.length/2-1;i>=0;i--){ heaplify(nums,i,k); } } public void heaplify(int nums[],int i,int k){ int minIndex=i; while(true){ if(i*2+1<k&&nums[i*2+1]<nums[minIndex]) minIndex=i*2+1; if(i*2+2<k&&nums[i*2+2]<nums[minIndex]) minIndex=i*2+2; if(i==minIndex) break; swap(nums,i,minIndex); i=minIndex; } } public void swap(int nums[],int i,int j){ int temp=nums[i]; nums[i]=nums[j]; nums[j]=temp; } } /** * Your KthLargest object will be instantiated and called as such: * KthLargest obj = new KthLargest(k, nums); * int param_1 = obj.add(val); */
Really Absolute
class KthLargest { PriorityQueue<Integer> pq; int k; public KthLargest(int k, int[] nums) { this.k = k; pq = new PriorityQueue<Integer>(); for (int x : nums) { add(x); } } public int add(int val) { pq.offer(val); if (pq.size() > k) { pq.poll(); } return pq.peek(); } }
60 Swordfinger Offer II 060. The k most frequently occurring digits
Given an array of integers nums and an integer k, return the element with the highest K frequency before it appears. The answer can be returned in any order.
Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
Solving ideas:
class Solution { Map<Integer,Integer>map=new HashMap(); //Solving ideas, hash table + heap, number of occurrences of hash table statistics, number of occurrences of heap maintenance k digits public int[] topKFrequent(int[] nums, int k) { for(int i=0;i<nums.length;i++){ map.put(nums[i],map.getOrDefault(nums[i],0)+1); } Set entrySet=map.entrySet(); Map.Entry entry[]=new Map.Entry [k]; int cur=0; for(Object ent:entrySet){ if(cur<k) entry[cur++]= (Map.Entry)ent; else break; } buildHeap(entry,k);//Create a heap of size k first cur=0; for(Object ent:entrySet){ if(cur>=k){ Map.Entry m=(Map.Entry)ent; if((int)m.getValue()>(int)entry[0].getValue()){ entry[0]=m; heapify(entry, 0, k); } } cur++; } int res[]=new int[k]; for(int i=0;i<k;i++){ res[i]=(int)entry[i].getKey(); } return res; } public void buildHeap(Map.Entry entry[], int k){ for(int i=k/2-1;i>=0;i--){ heapify(entry,i,k); } } public void heapify(Map.Entry entry[],int i,int k){ int minIndex=i; while(true){ if(i*2+1<k&&(int)entry[i*2+1].getValue()<(int)entry[minIndex].getValue()) minIndex=i*2+1; if(i*2+2<k&&(int)entry[i*2+2].getValue()<(int)entry[minIndex].getValue()) minIndex=i*2+2; if(minIndex==i) break; swap(entry,i,minIndex); i=minIndex; } } public void swap( Map.Entry entry[],int i,int j){ Map.Entry temp=entry[i]; entry[i]=entry[j]; entry[j]=temp; } }
Priority Queue
class Solution { public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>(); for (int num : nums) { occurrences.put(num, occurrences.getOrDefault(num, 0) + 1); } // The first element of int[] represents the value of the array, and the second element represents the number of times the value occurs PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() { public int compare(int[] m, int[] n) { return m[1] - n[1]; } }); for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) { int num = entry.getKey(), count = entry.getValue(); if (queue.size() == k) { if (queue.peek()[1] < count) { queue.poll(); queue.offer(new int[]{num, count}); } } else { queue.offer(new int[]{num, count}); } } int[] ret = new int[k]; for (int i = 0; i < k; ++i) { ret[i] = queue.poll()[0]; } return ret; } } Author: LeetCode-Solution Links: https://leetcode-cn.com/problems/top-k-frequent-elements/solution/qian-k-ge-gao-pin-yuan-su-by-leetcode-solution/ Source: Force buckle ( LeetCode) Copyright is owned by the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.
61 Swordfinger Offer II 061. and minimum k pairs
Given two arrays of integers nums1 and nums2 in ascending order, and an integer k.
Define a pair of values (u,v), where the first element comes from nums1 and the second from nums2.
Please find the minimum k pairs (u1,v1), (u2,v2)... (uk,vk).
Example 1:
Input: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
Output: [1,2], [1,4], [1,6]
Interpretation: Returns the first 3 logarithms in the sequence:
[1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]
Example 2:
Input: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
Output: [1,1], [1,1]
Interpretation: Returns the first 2 logarithms in the sequence:
[1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]
Example 3:
Input: nums1 = [1,2], nums2 = [3], k = 3
Output: [1,3], [2,3]
Interpretation: It is also possible that all pairs of numbers in the sequence are returned: [1,3], [2,3]
Source: LeetCode
Links: https://leetcode-cn.com/problems/qn8gGX
Copyright shall be owned by the withholding network. For commercial reprinting, please contact the official authorization. For non-commercial reprinting, please indicate the source.
Solving ideas, using priority queues, big root heaps
class Solution { public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { //Solving problems, priority queue to build big root heap List<List<Integer>>list=new ArrayList(); PriorityQueue<int[]>queue=new PriorityQueue<int[]>((int []a,int[]b)->(b[0]+b[1])-(a[0]+a[1]));//Note how the comparator is written. By default, it is a small root heap. Constructing a large root heap requires defining a constructor. for(int i=0;i<nums1.length;i++){ for(int j=0;j<nums2.length;j++){ int temp[]=new int[]{nums1[i],nums2[j]}; if(queue.size()<k){ queue.offer(temp); }else{ if(temp[0]+temp[1]<queue.peek()[0]+queue.peek()[1]){ queue.poll(); queue.offer(temp); }else{ break;//Notice the ascending order } } } } //int size=queue.size(); for(int i=0;i<k;i++){ if(!queue.isEmpty()){ int temp1[]=queue.poll(); List<Integer> list1 = Arrays.asList(temp1[0],temp1[1]); list.add(list1); } } return list; } }
class Solution { public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) { List<List<Integer>> res = new ArrayList<>(); PriorityQueue<int[]> pq = new PriorityQueue<>(k, (o1, o2)->(o2[0] + o2[1] - o1[0] - o1[1])); for(int i = 0; i < Math.min(nums1.length, k); i++){ for(int j = 0; j < Math.min(nums2.length, k); j++){ if(pq.size() == k && nums1[i] + nums2[j] >= pq.peek()[0] + pq.peek()[1]) break; if(pq.size() == k) pq.poll(); pq.offer(new int[]{nums1[i], nums2[j]}); } } for(int i = 0; i < k && pq.size() > 0; i++){ int[] temp = pq.poll(); List<Integer> list = new ArrayList<>(); list.add(temp[0]); list.add(temp[1]); res.add(list); } return res; } }