Sword finger offer (V): search algorithm
Topic 1: repeated numbers in the array
Method 1: hash table / Set. It's the same way, but there's no easy answer
class Solution { public int findRepeatNumber(int[] nums) { Set<Integer> dic = new HashSet<>(); for(int num : nums) { if(dic.contains(num)) return num; dic.add(num); } return -1; } }
Method 2: in situ exchange
By traversing the array and making the index of the element correspond to the value one by one through the exchange operation, the corresponding value can be mapped through the index, which is equivalent to the dictionary.
class Solution { public int findRepeatNumber(int[] nums) { int i = 0; while(i < nums.length) { //If the index is equal to the corresponding value, skip if(nums[i] == i) { i++; continue; } //If a value is traversed, the element values at num [i] and index I are both num [i] when the following formula is equal, that is, a group of duplicate values are found and returned if(nums[nums[i]] == nums[i]) return nums[i]; int tmp = nums[i]; nums[i] = nums[tmp]; nums[tmp] = tmp; } return -1; } }
Topic 2: search in two-dimensional array
Find a number in the ordered two-dimensional array. The stupid method uses binary search for each row. The time complexity is NlogN, which is no less than N^2 of the violence scheme;
class Solution { int[][] matrix; int n,target; public boolean findNumberIn2DArray(int[][] matrix, int target) { this.matrix = matrix; int m = matrix.length; if (m==0)return false; this.n = matrix[0].length; if (n==0)return false; this.target = target; for (int i = 0; i < m; i++) { if (matrix[i][n-1]<target)continue; else { //Judge each line if (recursionBinarySearch(matrix[i],target,0,matrix[i].length-1)>=0)return true; } } return false; } //Perform binary search int recursionBinarySearch(int[] arr,int key,int low,int high){ if(key < arr[low] || key > arr[high] || low > high){ return -1; } int middle = (low + high) / 2; //Initial intermediate position if(arr[middle] > key){ //If it is larger than the keyword, the keyword is in the left area return recursionBinarySearch(arr, key, low, middle - 1); }else if(arr[middle] < key){ //Smaller than the keyword, the keyword is in the right area return recursionBinarySearch(arr, key, middle + 1, high); }else { return middle; } } }
Method 2: similar to tree access, direct call advanced
Idea: start the search from the "root node". If you encounter an element larger than target, you will turn left, otherwise you will turn right to find the target value target.
class Solution { public boolean findNumberIn2DArray(int[][] matrix, int target) { int i = matrix.length - 1, j = 0; //i is reduced to 0 at most, and j is the line length minus one at most while(i >= 0 && j < matrix[0].length) { if(matrix[i][j] > target) i--; else if(matrix[i][j] < target) j++; else return true; } return false; } }
Topic 3: rotate the minimum number of the array
The violence method actually ran through, and the time complexity was also very good, but it was not appropriate to do so. The correct answer was to use two-point search
Method 1: Violence Law
class Solution { public int minArray(int[] numbers) { if (numbers.length==0)return 0; int res=0; for (int i = 0; i < numbers.length-1; i++) { if (numbers[i+1]-numbers[i]<0){ res = i+1; break; } } return numbers[res]; } }
Method 2: binary search
Key points
- The midpoint of each dichotomy is compared with the right boundary
- Reduced interval security when the comparison values are the same
class Solution { public int minArray(int[] numbers) { int i = 0, j = numbers.length - 1; while (i < j) { int m = (i + j) / 2; if (numbers[m] > numbers[j]) i = m + 1; else if (numbers[m] < numbers[j]) j = m; else { int x = i; for(int k = i + 1; k < j; k++) { if(numbers[k] < numbers[x]) x = k; } return numbers[x]; } } return numbers[i]; } }
Title 4: the first character that appears only once
Method 1: use two set s and a character array
class Solution { public char firstUniqChar(String s) { char reschar = ' '; if (s.length()==0)return reschar; char[] tem = new char[s.length()]; Set<Character> res = new HashSet<>(); Set<Character> res1 = new HashSet<>(); for (int i = 0; i < s.length(); i++) { char cur = s.charAt(i); if (res.contains(cur)){ res1.add(cur); } res.add(cur); tem[i] = cur; } for (int j = 0; j < tem.length; j++) { if (!res1.contains(tem[j])){ reschar = tem[j]; break; } } return reschar; } }
Method 2: hash table – > HashMap < character, Boolean > whether a character is saved and whether it appears once is too subtle
class Solution { public char firstUniqChar(String s) { HashMap<Character, Boolean> dic = new HashMap<>(); char[] sc = s.toCharArray(); for(char c : sc) dic.put(c, !dic.containsKey(c)); for(char c : sc) if(dic.get(c)) return c; return ' '; } }
Method 3: ordered hash table – > LinkedHashMap
Key value pairs in an ordered hash table are sorted in insertion order. Based on this, you can search the first "number of 1 characters" by traversing the ordered hash table.
class Solution { public char firstUniqChar(String s) { //LinkedHashMap is an ordered hash table Map<Character, Boolean> dic = new LinkedHashMap<>(); char[] sc = s.toCharArray(); for(char c : sc) dic.put(c, !dic.containsKey(c)); //The access method of hash table is worth learning for(Map.Entry<Character, Boolean> d : dic.entrySet()){ if(d.getValue()) return d.getKey(); } return ' '; } }
Topic 5: find the number I in the sorted array
Use the binary search method to find the left and right boundaries. The key is how to find the left and right boundaries
class Solution { public int search(int[] nums, int target) { // Search right boundary int i = 0, j = nums.length - 1; while(i <= j) { int m = (i + j) / 2; if(nums[m] <= target) i = m + 1; else j = m - 1; } int right = i; // If there is no target in the array, it will be returned in advance if(j >= 0 && nums[j] != target) return 0; // Search left border right i = 0; j = nums.length - 1; while(i <= j) { int m = (i + j) / 2; if(nums[m] < target) i = m + 1; else j = m - 1; } int left = j; return right - left - 1; } } //The above methods are cumbersome class Solution { public int search(int[] nums, int target) { return helper(nums, target) - helper(nums, target - 1); } int helper(int[] nums, int tar) { int i = 0, j = nums.length - 1; while(i <= j) { int m = (i + j) / 2; if(nums[m] <= tar) i = m + 1; else j = m - 1; } return i; } }
Title 6: missing numbers in 0 ~ n-1
class Solution { public int missingNumber(int[] nums) { int i = 0, j = nums.length-1; while (i<=j){ int m = (i+j)/2; if (nums[m]==m)i=m+1; else j=m-1; } return i; } }