二分查找

704.二分查找(简单) 标准二分查找

  1. class Solution {
  2. public int search(int[] nums, int target) {
  3. int low = 0, high = nums.length -1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if(nums[mid] == target) {
  7. return mid;
  8. } else if (nums[mid] > target) {
  9. high = mid - 1;
  10. } else {
  11. low = mid + 1;
  12. }
  13. }
  14. return -1;
  15. }
  16. }

374.猜数字大小(简单)

解题思路:二分法

  1. public class Solution extends GuessGame {
  2. public int guessNumber(int n) {
  3. return bisection(0, n);
  4. }
  5. public int bisection(int low, int high) {
  6. while(low <= high) {
  7. int mid = low + (high - low) / 2;
  8. int guessRes = guess(mid);
  9. if(guessRes == 0) {
  10. return mid;
  11. } else if(guessRes == -1) {
  12. high = mid - 1;
  13. } else {
  14. low = mid + 1;
  15. }
  16. }
  17. return 0;
  18. }
  19. }

744.寻找比目标字母大的最小字母(简单)

解题思路:

  1. class Solution {
  2. public char nextGreatestLetter(char[] letters, char target) {
  3. int size = letters.length, low = 0, high = size - 1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. char midChar = letters[mid];
  7. if(midChar <= target) {
  8. if(mid == high || letters[mid + 1] > target) {
  9. // 循环数组
  10. return letters[(mid + 1) % size];
  11. }
  12. low = mid + 1;
  13. } else{
  14. high = mid - 1;
  15. }
  16. }
  17. return letters[0];
  18. }
  19. }

35.搜索插入位置(简单)

  1. class Solution {
  2. public int searchInsert(int[] nums, int target) {
  3. int size = nums.length, low = 0, high = size - 1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if(nums[mid] == target) {
  7. return mid;
  8. } else if(nums[mid] < target) {
  9. if(mid == size - 1 || nums[mid + 1] > target) {
  10. return mid + 1;
  11. }
  12. low = mid + 1;
  13. } else {
  14. if(mid == 0 || nums[mid - 1] < target) {
  15. return mid;
  16. }
  17. high = mid - 1;
  18. }
  19. }
  20. return -1;
  21. }
  22. }

34.在排序数组中查找元素的第一个和最后一个位置 (中等)

  1. class Solution {
  2. public int[] searchRange(int[] nums, int target) {
  3. int low = 0, high = nums.length - 1, size = nums.length;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if(nums[mid] == target) {
  7. int s = 0, e = 0, i = mid;
  8. while(i >= 0 && nums[i] == target) {
  9. i--;
  10. }
  11. // 本身多减了一次
  12. s = i + 1;
  13. i = mid;
  14. while(i < size && nums[i] == target) {
  15. i++;
  16. }
  17. // 多加了一次
  18. e = i - 1;
  19. return new int[] {s, e};
  20. } else if (nums[mid] < target) {
  21. low = mid + 1;
  22. } else {
  23. high = mid - 1;
  24. }
  25. }
  26. return new int[]{-1, -1};
  27. }
  28. }

面试题10.05.稀疏数组搜索(简单)

  1. class Solution {
  2. public int findString(String[] words, String s) {
  3. int low = 0, high = words.length - 1, size = words.length;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. // 遇到空字符串,往后遍历
  7. while(mid > low && "".equals(words[mid])){
  8. mid--;
  9. }
  10. if(words[mid].compareTo(s) == 0) {
  11. return mid;
  12. } else if (words[mid].compareTo(s) < 0) {
  13. low = mid + 1;
  14. } else {
  15. high = mid - 1;
  16. }
  17. }
  18. return -1;
  19. }
  20. }

33.搜索旋转排序数组(中等)无重复数据

二分法

解题思路:

  1. class Solution {
  2. public int search(int[] nums, int target) {
  3. int low = 0, high = nums.length - 1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if(nums[mid] == target) {
  7. return mid;
  8. } else if(nums[mid] > target) {
  9. // 向右遍历探测有无小于等于target的值
  10. int i = mid;
  11. while(i <= high && nums[i] > target) {
  12. i++;
  13. }
  14. // 右侧找到比target小的值,判断target在不在[i, high] 这个区间
  15. if(i <= high && nums[i] <= target && nums[high] >= target){
  16. low = i;
  17. } else {
  18. high = mid - 1;
  19. }
  20. } else {
  21. // 向左遍历探测有无大于等于target的值
  22. int i = mid;
  23. while(i >= low && nums[i] < target) {
  24. i--;
  25. }
  26. // 左侧找到比target大的值,判断target在不在[low, i] 这个区间内
  27. if(i >= low && nums[low] <= target && nums[i] >= target) {
  28. high = i;
  29. } else {
  30. low = mid + 1;
  31. }
  32. }
  33. }
  34. return -1;
  35. }
  36. }

153.寻找旋转排序数组中的最小值(中等) 无重复数据

  1. class Solution {
  2. public int findMin(int[] nums) {
  3. int low = 0, high = nums.length - 1, size = nums.length;
  4. if(size== 1) {
  5. return nums[0];
  6. }
  7. while(low <= high) {
  8. int mid = low + (high - low) / 2;
  9. if((mid == 0 && nums[mid] < nums[mid + 1])
  10. || (mid == size -1 && nums[mid] < nums[mid - 1])
  11. || (mid > 0 && mid < size - 1 && nums[mid] < nums[mid - 1] && nums[mid] < nums[mid + 1])){
  12. return nums[mid];
  13. }
  14. if(mid < size && nums[mid] < nums[mid + 1]) {
  15. // 向右探测有无降序元素
  16. if(nums[high] <= nums[mid]) {
  17. low = mid + 1;
  18. }else {
  19. high = mid - 1;
  20. }
  21. } else {
  22. low = mid + 1;
  23. }
  24. }
  25. return -1;
  26. }
  27. }

852.山脉数组的峰顶索引(简单)峰值二分

  1. class Solution {
  2. public int peakIndexInMountainArray(int[] arr) {
  3. int length = arr.length, low = 0, high = length - 1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if(mid > 0 && mid < length - 1 && arr[mid] > arr[mid - 1] && arr[mid] > arr[mid + 1]) {
  7. return mid;
  8. }
  9. if(arr[mid] <= arr[mid + 1]) {
  10. low = mid + 1;
  11. } else {
  12. high = mid - 1;
  13. }
  14. }
  15. return -1;
  16. }
  17. }

162.寻找峰值(中等)峰值二分

  1. class Solution {
  2. public int findPeakElement(int[] nums) {
  3. int low = 0, high = nums.length -1;
  4. if(nums.length == 1) {
  5. return 0;
  6. }
  7. while(low <= high) {
  8. int mid = low + (high - low) / 2;
  9. if((mid == nums.length -1 && nums[mid] > nums[mid - 1])
  10. || (mid == 0 && nums[mid] > nums[mid + 1])
  11. || (mid > 0 && mid < nums.length - 1 && nums[mid] > nums[mid - 1] && nums[mid] > nums[mid + 1])) {
  12. return mid;
  13. }
  14. if(nums[mid] < nums[mid + 1]) {
  15. low = mid + 1;
  16. } else {
  17. high = mid - 1;
  18. }
  19. }
  20. return -1;
  21. }
  22. }

367.有效的完全平方数(简单)二分答案

  1. class Solution {
  2. public boolean isPerfectSquare(int num) {
  3. long low = 0, high = num;
  4. while(low <= high) {
  5. long mid = low + (high - low) / 2;
  6. // 使用 long 防止溢出
  7. long sqrt = mid * mid;
  8. if(sqrt == num) {
  9. return true;
  10. }
  11. if(sqrt > num) {
  12. high = mid - 1;
  13. } else {
  14. low = mid + 1;
  15. }
  16. }
  17. return false;
  18. }
  19. }

69. x的平方根(简单)二分答案

二分法

  1. class Solution {
  2. public int mySqrt(int x) {
  3. int low = 0, high = x, res = -1;
  4. while(low <= high) {
  5. int mid = low + (high - low) / 2;
  6. if((long)mid * mid <= x) {
  7. res = mid;
  8. low = mid + 1;
  9. } else {
  10. high = mid - 1;
  11. }
  12. }
  13. return res;
  14. }
  15. }

74.搜索二维矩阵(中等) 二维转一维,二分查找

  1. class Solution {
  2. public boolean searchMatrix(int[][] matrix, int target) {
  3. int r = matrix.length, c = matrix[0].length;
  4. for(int i = 0; i < r; i++) {
  5. if(target >= matrix[i][0] && target <= matrix[i][c - 1]) {
  6. return bisection(matrix[i], target);
  7. }
  8. }
  9. return false;
  10. }
  11. private boolean bisection(int[] nums, int target) {
  12. int low = 0, high = nums.length - 1;
  13. while(low <= high) {
  14. int mid = low + (high - low) / 2;
  15. if(nums[mid] == target) {
  16. return true;
  17. } else if(nums[mid] < target) {
  18. low = mid + 1;
  19. } else {
  20. high = mid - 1;
  21. }
  22. }
  23. return false;
  24. }
  25. }

658. 找到 K 个最接近的元素(中等)

二分法+双指针

  1. class Solution {
  2. public List<Integer> findClosestElements(int[] arr, int k, int x) {
  3. int low = 0, high = arr.length - 1, mid = 0;
  4. int left = -1, right = -1;
  5. while(low <= high) {
  6. mid = low + (high - low) / 2;
  7. if(arr[mid] == x) {
  8. left = right = mid;
  9. if(mid == 0) {
  10. right = k - 1;
  11. } else if (mid == arr.length -1) {
  12. left = mid - k + 1;
  13. } else {
  14. int[] range = findK(arr, mid, k, x);
  15. left = range[0];
  16. right = range[1];
  17. }
  18. break;
  19. } else if(arr[mid] < x) {
  20. low = mid + 1;
  21. } else {
  22. high = mid - 1;
  23. }
  24. }
  25. if(low > high) {
  26. int[] range = findK(arr, low, k, x);
  27. left = range[0];
  28. right = range[1];
  29. }
  30. List<Integer> res = new ArrayList<>();
  31. for(int i = left; i <= right; i++) {
  32. res.add(arr[i]);
  33. }
  34. return res;
  35. }
  36. private boolean compare(int[] arr, int a, int b, int x) {
  37. if(a < 0) {
  38. return false;
  39. }
  40. if(b > arr.length - 1) {
  41. return true;
  42. }
  43. return Math.abs(arr[a] - x) <= Math.abs(arr[b] - x);
  44. }
  45. private int[] findK(int[] arr, int mid, int k, int x) {
  46. int left = Math.max(0, mid - k - 1), right = Math.min(arr.length - 1, mid + k - 1);
  47. while(right - left > k - 1) {
  48. if(compare(arr, left, right, x)){
  49. right--;
  50. } else {
  51. left++;
  52. }
  53. }
  54. return new int[]{left, right};
  55. }
  56. }

875. 爱吃香蕉的珂珂(中等)二分答案

81. 搜索旋转排序数组 II(中等)有重复数据

154. 寻找旋转排序数组中的最小值 II (困难) 有重复数据

哈希表

两数之和 (简单)

哈希表

  1. class Solution {
  2. public int[] twoSum(int[] nums, int target) {
  3. Map<Integer, Integer> map = new HashMap<>();
  4. for (int i = 0; i < nums.length; i++) {
  5. int key = target - nums[i];
  6. if (map.containsKey(key)) {
  7. return new int[]{map.get(key), i};
  8. }
  9. map.put(nums[i], i);
  10. }
  11. return null;
  12. }
  13. }

15.三数之和(中等)

哈希表
  1. class Solution {
  2. public List<List<Integer>> threeSum(int[] nums) {
  3. List<List<Integer>> resList = new ArrayList<>();
  4. Map<Integer, Integer> map = new HashMap<>();
  5. Arrays.sort(nums);
  6. int size = nums.length;
  7. if(size < 3 || nums[0] > 0) {
  8. return resList;
  9. }
  10. for(int i = 0; i < size; i++) {
  11. map.put(nums[i], i);
  12. }
  13. for(int i = 0; i < size; i++) {
  14. if(i > 0 && nums[i] == nums[i - 1]) {
  15. continue;
  16. }
  17. for(int j = i + 1; j < size; j++) {
  18. if(i != j - 1 && nums[j] == nums[j - 1]) {
  19. continue;
  20. }
  21. int target = -(nums[i] + nums[j]);
  22. if(map.containsKey(target)) {
  23. int idx = map.get(target);
  24. if(idx > j) {
  25. List<Integer> list = new ArrayList<>();
  26. list.add(nums[i]);
  27. list.add(nums[j]);
  28. list.add(nums[idx]);
  29. resList.add(list);
  30. }
  31. }
  32. }
  33. }
  34. return resList;
  35. }
  36. }

排序+头尾双指针

解题思路:

  1. class Solution {
  2. public List<List<Integer>> threeSum(int[] nums) {
  3. List<List<Integer>> result = new ArrayList<>();
  4. Arrays.sort(nums);
  5. if(nums == null || nums.length < 3 || nums[0] > 0) {
  6. return result;
  7. }
  8. int size = nums.length;
  9. for(int i = 0; i < size; i++) {
  10. if(i != 0 && nums[i] == nums[i -1]) {
  11. continue;
  12. }
  13. int target = -nums[i];
  14. int head = i + 1, tail = size - 1;
  15. while(head < tail) {
  16. int sum = nums[head] + nums[tail];
  17. if((target == sum)) {
  18. List<Integer> list = new ArrayList<>();
  19. list.add(nums[i]);
  20. list.add(nums[head]);
  21. list.add(nums[tail]);
  22. result.add(list);
  23. head++;
  24. tail--;
  25. // 去除左侧重复的元素
  26. while(head < tail && nums[head] == nums[head - 1]) {
  27. head++;
  28. }
  29. // 去除右侧重复的元素
  30. while(head < tail && nums[tail] == nums[tail + 1]){
  31. tail--;
  32. }
  33. } else if(sum > target){
  34. tail--;
  35. } else {
  36. head++;
  37. }
  38. }
  39. }
  40. return result;
  41. }
  42. }

160.相交链表(简单)

  1. public class Solution {
  2. public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  3. if(headA == null || headB == null) {
  4. return null;
  5. }
  6. Map<ListNode, ListNode> map = new HashMap<>();
  7. ListNode tmp = headA;
  8. while(tmp != null) {
  9. map.put(tmp, tmp);
  10. tmp = tmp.next;
  11. }
  12. while(headB != null) {
  13. if(map.containsKey(headB)) {
  14. return headB;
  15. }
  16. headB = headB.next;
  17. }
  18. return headB;
  19. }
  20. }

141.环形链表(简单)

  1. public class Solution {
  2. public boolean hasCycle(ListNode head) {
  3. Map<ListNode, Integer> map = new HashMap<>();
  4. while(head != null) {
  5. if(map.containsKey(head)) {
  6. return true;
  7. }
  8. map.put(head, 1);
  9. head = head.next;
  10. }
  11. return false;
  12. }
  13. }

面试题02.01.移除重复节点(中等)

  1. class Solution {
  2. public ListNode removeDuplicateNodes(ListNode head) {
  3. Map<Integer, Boolean> map = new HashMap<>();
  4. ListNode newHead = new ListNode(-1), tmp = head, pre = newHead;
  5. newHead.next = tmp;
  6. while(tmp != null) {
  7. if(map.containsKey(tmp.val)) {
  8. pre.next = tmp.next;
  9. tmp = tmp.next;
  10. continue;
  11. }
  12. map.put(tmp.val, true);
  13. pre = tmp;
  14. tmp = tmp.next;
  15. }
  16. pre.next = null;
  17. return head;
  18. }
  19. }

面试题16.02.单词频率 (简单)

  1. class WordsFrequency {
  2. Map<String, Integer> map;
  3. public WordsFrequency(String[] book) {
  4. map = new HashMap<>(book.length);
  5. for(String val : book) {
  6. if(map.containsKey(val)) {
  7. map.put(val, map.get(val) + 1);
  8. } else {
  9. map.put(val, 1);
  10. }
  11. }
  12. }
  13. public int get(String word) {
  14. if(!map.containsKey(word)) {
  15. return 0;
  16. }
  17. return map.get(word);
  18. }
  19. }

面试题01.02.判定是否互为字符重排(简单)

  1. class Solution {
  2. public boolean CheckPermutation(String s1, String s2) {
  3. if(s1 == null && s2 == null) {
  4. return true;
  5. }
  6. if(s1.length() != s2.length()) {
  7. return false;
  8. }
  9. Map<Character, Integer> map = new HashMap<>();
  10. for(int i = 0; i < s1.length(); i++) {
  11. Character key = s1.charAt(i);
  12. if(map.containsKey(key)) {
  13. map.put(key, map.get(key) + 1);
  14. } else {
  15. map.put(key, 1);
  16. }
  17. }
  18. for(int i = 0; i < s2.length(); i++) {
  19. Character key = s2.charAt(i);
  20. if(!map.containsKey(key)) {
  21. return false;
  22. }
  23. map.put(key, map.get(key) - 1);
  24. }
  25. for(Map.Entry<Character,Integer> entry : map.entrySet()) {
  26. if(entry.getValue() != 0) {
  27. return false;
  28. }
  29. }
  30. return true;
  31. }
  32. }

剑指Offer 03.数组中重复的数字 (简单)

哈希表
  1. class Solution {
  2. public int findRepeatNumber(int[] nums) {
  3. Map<Integer, Integer> map = new HashMap<>();
  4. for(int val : nums) {
  5. if(map.containsKey(val)) {
  6. return val;
  7. }
  8. map.put(val, val);
  9. }
  10. return -1;
  11. }
  12. }

数组原地交换

解题思路:

  1. class Solution {
  2. public int findRepeatNumber(int[] nums) {
  3. int i = 0;
  4. while(i < nums.length) {
  5. if(nums[i] == i) {
  6. i++;
  7. continue;
  8. }
  9. if(nums[nums[i]] == nums[i]) {
  10. return nums[i];
  11. }
  12. int t = nums[i];
  13. nums[i] = nums[t];
  14. nums[t] = t;
  15. }
  16. return -1;
  17. }
  18. }

时间复杂度:O(n)
空间复杂度:O(1)

242.有效的字母异位词(简单)

哈希表(两个哈希表,减少遍历次数)
  1. class Solution {
  2. public boolean isAnagram(String s, String t) {
  3. if (s.length() != t.length()) {
  4. return false;
  5. }
  6. char[] s1 = s.toCharArray();
  7. char[] t1 = t.toCharArray();
  8. char[] counters = new char[26];
  9. char[] countert = new char[26];
  10. for (int i = 0; i < s1.length; i++) {
  11. counters[s1[i] - 'a']++;
  12. countert[t1[i] - 'a']++;
  13. }
  14. for (int i = 0; i < counters.length; i++) {
  15. if (counters[i] != countert[i]) {
  16. return false;
  17. }
  18. }
  19. return true;
  20. }
  21. }

时间复杂度:O(n)
空间复杂度:O(2n) => O(n)

49.字母异位词分组(中等)

哈希表
  1. class Solution {
  2. public List<List<String>> groupAnagrams(String[] strs) {
  3. Map<String, List<String>> hashMap = new HashMap<>();
  4. List<List<String>> result = new ArrayList<>();
  5. for(String str : strs) {
  6. String key = getKey(str);
  7. List<String> list = hashMap.getOrDefault(key, new ArrayList<>());
  8. list.add(str);
  9. hashMap.put(key, list);
  10. }
  11. for(Map.Entry<String, List<String>> entry : hashMap.entrySet()) {
  12. result.add(entry.getValue());
  13. }
  14. return result;
  15. }
  16. // 字母异位词的共性:每个字母的个数都是一致的。利用这个特性构造通用的组合key => 字母+出现的次数
  17. private String getKey(String str) {
  18. int[] map = new int[26];
  19. for(int i = 0; i < str.length(); i++) {
  20. map[str.charAt(i) - 'a']++;
  21. }
  22. StringBuilder sb = new StringBuilder();
  23. for(int i = 0; i < map.length; i++) {
  24. if(map[i] != 0) {
  25. sb.append((char)(i + 'a')).append(map[i]);
  26. }
  27. }
  28. return sb.toString();
  29. }
  30. }

时间复杂度:O(n)
空间度复杂度:O(n)

136.只出现一次的数字(简单)

哈希表
  1. class Solution {
  2. public int singleNumber(int[] nums) {
  3. Map<Integer, Integer> map = new HashMap<>();
  4. for(int val : nums) {
  5. if(map.containsKey(val)) {
  6. map.put(val, map.get(val) + 1);
  7. } else {
  8. map.put(val, 1);
  9. }
  10. }
  11. for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
  12. if(entry.getValue() == 1) {
  13. return entry.getKey();
  14. }
  15. }
  16. return -1;
  17. }
  18. }

时间复杂度:O(n)
空间复杂度:O(n)

异或运算
  1. class Solution {
  2. public int singleNumber(int[] nums) {
  3. // 异或运算
  4. // 1. 0与任意数 a 异或,其结果都是 a
  5. // 2. 任意数和自身异或,结果都为 0
  6. // 3. 异或运算满足交换律和结合律
  7. int single = 0;
  8. for(int val : nums) {
  9. single ^= val;
  10. }
  11. return single;
  12. }
  13. }

时间复杂度:O(n)
空间复杂度:O(1)

349.两个数组的交集 (简单)

哈希表
  1. class Solution {
  2. public int[] intersection(int[] nums1, int[] nums2) {
  3. Set<Integer> set = new HashSet<>();
  4. Set<Integer> resSet = new HashSet<>();
  5. for(int i = 0; i <nums1.length; i++) {
  6. set.add(nums1[i]);
  7. }
  8. for(int i = 0; i < nums2.length; i++) {
  9. if(set.contains(nums2[i])) {
  10. resSet.add(nums2[i]);
  11. }
  12. }
  13. int[] res = new int[resSet.size()];
  14. int i = 0;
  15. Iterator<Integer> iterator = resSet.iterator();
  16. while(iterator.hasNext()) {
  17. res[i++] = iterator.next();
  18. }
  19. return res;
  20. }
  21. }

1122.数组的相对排序(中等)

哈希表

解题思路:

  1. class Solution {
  2. public int[] relativeSortArray(int[] arr1, int[] arr2) {
  3. Map<Integer, Integer> map = new HashMap<>();
  4. // 初始化 map
  5. for(int val : arr2) {
  6. map.put(val, 0);
  7. }
  8. // 扫描 arr1 统计 arr2 中每个数字在 arr1 中出现的次数
  9. for(int val : arr1) {
  10. if(map.containsKey(val)) {
  11. int oldCount = map.get(val);
  12. map.put(val, oldCount + 1);
  13. }
  14. }
  15. int[] result = new int[arr1.length];
  16. int k = 0;
  17. for(int key : arr2) {
  18. int count = map.get(key);
  19. while(count > 0) {
  20. result[k++] = key;
  21. count--;
  22. }
  23. }
  24. Arrays.sort(arr1);
  25. for(int v : arr1) {
  26. if(!map.containsKey(v)) {
  27. result[k++] = v;
  28. }
  29. }
  30. return result;
  31. }
  32. }

首尾双指针+排序
  1. class Solution {
  2. public int[] relativeSortArray(int[] arr1, int[] arr2) {
  3. if(arr1.length == 0 || arr2.length == 0) {
  4. return arr1;
  5. }
  6. int flag = 0;
  7. for(int i = 0; i < arr2.length; i++) {
  8. int target = arr2[i];
  9. int head = flag, tail = arr1.length - 1;
  10. while(head <= tail) {
  11. if(arr1[tail] == target) {
  12. int t = arr1[tail];
  13. arr1[tail] = arr1[head];
  14. arr1[head] = t;
  15. head++;
  16. } else {
  17. tail--;
  18. }
  19. }
  20. flag = head;
  21. }
  22. int[] tmp = Arrays.copyOfRange(arr1, flag, arr1.length);
  23. Arrays.sort(tmp);
  24. for(int i = 0; i < tmp.length; i++) {
  25. arr1[i + flag] = tmp[i];
  26. }
  27. return arr1;
  28. }
  29. }

706.设计哈希映射(简单)

超大数组
  1. class MyHashMap {
  2. private int[] map;
  3. /** Initialize your data structure here. */
  4. public MyHashMap() {
  5. map = new int[1000001];
  6. Arrays.fill(map, -1);
  7. }
  8. /** value will always be non-negative. */
  9. public void put(int key, int value) {
  10. map[key] = value;
  11. }
  12. /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
  13. public int get(int key) {
  14. return map[key];
  15. }
  16. /** Removes the mapping of the specified value key if this map contains a mapping for the key */
  17. public void remove(int key) {
  18. map[key] = -1;
  19. }
  20. }
  21. /**
  22. * Your MyHashMap object will be instantiated and called as such:
  23. * MyHashMap obj = new MyHashMap();
  24. * obj.put(key,value);
  25. * int param_2 = obj.get(key);
  26. * obj.remove(key);
  27. */

链地址法

解题思路:

  1. 基于数组实现哈希表
  2. 自定义计算hash的函数:取模运算。
  3. 基于链地址法解决哈希冲突。 ```java class MyHashMap {

    class Node {

    1. int key;
    2. int value;
    3. public Node(int key, int value) {
    4. this.key = key;
    5. this.value = value;
    6. }

    }

    private int BASE = 769;

    private LinkedList[] data;

    /* Initialize your data structure here. / public MyHashMap() {

    1. data = new LinkedList[BASE];

    }

    /* value will always be non-negative. / public void put(int key, int value) {

    1. int idx = hash(key);
    2. if(data[idx] == null) {
    3. LinkedList<Node> list = new LinkedList<>();
    4. list.add(new Node(key, value));
    5. data[idx] = list;
    6. } else {
    7. for(Object n : data[idx]) {
    8. Node node = (Node) n;
    9. if(node.key == key) {
    10. node.value = value;
    11. return;
    12. }
    13. }
    14. data[idx].addLast(new Node(key, value));
    15. }

    }

    /* Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key / public int get(int key) {

    1. int idx = hash(key);
    2. if(data[idx] == null) {
    3. return -1;
    4. }
    5. for(Object n : data[idx]) {
    6. Node node = (Node) n;
    7. if(node.key == key) {
    8. return node.value;
    9. }
    10. }
    11. return -1;

    }

    /* Removes the mapping of the specified value key if this map contains a mapping for the key / public void remove(int key) {

    1. int idx = hash(key);
    2. if(data[idx] != null) {
    3. Iterator<Node> it = data[idx].iterator();
    4. while(it.hasNext()) {
    5. Node node = it.next();
    6. if(node.key == key) {
    7. data[idx].remove(node);
    8. return;
    9. }
    10. }
    11. }

    }

    private int hash(int key) {

    1. return key % BASE;

    } }

/**

  • Your MyHashMap object will be instantiated and called as such:
  • MyHashMap obj = new MyHashMap();
  • obj.put(key,value);
  • int param_2 = obj.get(key);
  • obj.remove(key); */ ```

146. LRU 缓存机制 (中等)标准的LRU

哈希表+双向链表

  1. class LRUCache {
  2. private static class DLNode {
  3. int key, value;
  4. DLNode prev, next;
  5. public DLNode() {
  6. }
  7. public DLNode(int key, int value) {
  8. this.key = key;
  9. this.value = value;
  10. }
  11. }
  12. private int capacity, size;
  13. private DLNode head, tail;
  14. private DLNode[] cache = new DLNode[30001];
  15. public LRUCache(int capacity) {
  16. this.size = 0;
  17. this.capacity = capacity;
  18. head = new DLNode();
  19. tail = new DLNode();
  20. head.next = tail;
  21. tail.prev = head;
  22. }
  23. public int get(int key) {
  24. DLNode node = cache[key];
  25. if (node == null) {
  26. return -1;
  27. }
  28. removeNode(node);
  29. insertNode(node);
  30. return node.value;
  31. }
  32. private void removeNode(DLNode node) {
  33. node.prev.next = node.next;
  34. node.next.prev = node.prev;
  35. }
  36. private void insertNode(DLNode node) {
  37. node.next = head.next;
  38. head.next.prev = node;
  39. node.prev = head;
  40. head.next = node;
  41. }
  42. public void put(int key, int value) {
  43. DLNode node = cache[key];
  44. if (node == null) {
  45. insertNode(cache[key] = new DLNode(key, value));
  46. size++;
  47. if (size > capacity) {
  48. DLNode last = tail.prev;
  49. removeNode(last);
  50. cache[last.key] = null;
  51. size--;
  52. }
  53. } else {
  54. node.value = value;
  55. removeNode(node);
  56. insertNode(node);
  57. }
  58. }
  59. }

面试题16.21.交换和(中等)

  1. class Solution {
  2. public int[] findSwapValues(int[] array1, int[] array2) {
  3. // 假设 s1 为 array1 的总和,s2 为 array2 的总和,a 为 array1 要交换的值,b 为 array2 要交换的值
  4. // s1 - a + b = s2 -b + a => b = (s2 - s1) / 2 + a
  5. // s2 - s1 为奇数时,则不存在符合的值。
  6. HashSet<Integer> set = new HashSet<>();
  7. int s1 = 0, s2 = 0;
  8. for(int val : array1) {
  9. s1 += val;
  10. }
  11. for(int val : array2) {
  12. s2 += val;
  13. set.add(val);
  14. }
  15. for(int val : array1) {
  16. //
  17. if(((s2 - s1) & 1) == 1) {
  18. return new int[0];
  19. }
  20. int target = val + (s2 - s1) / 2;
  21. if(set.contains(target)) {
  22. return new int[]{val, target};
  23. }
  24. }
  25. return new int[0];
  26. }
  27. }