Java快速开发学习

锁清秋

leetcode-数组

概要:需要了解一下知识:

  • 排序:选择排序;插入排序;归并排序;快速排序
  • 查找:二分查找法
  • 数据结构:栈;队列;堆

一、二分法查找

  1. private int sort(int key, int[] target, int left, int right) {
  2. if (left > right)
  3. return -1;
  4. int mid = (left + right) / 2;
  5. if (key < target[mid])
  6. return sort(key, target, left, mid - 1);
  7. if (key > target[mid])
  8. return sort(key, target, mid + 1, right);
  9. else
  10. return mid;
  11. }

2. 移动零

  1. 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
  2. 示例:
  3. 输入: [0,1,0,3,12]
  4. 输出: [1,3,12,0,0]
  5. 说明:
  6. 必须在原数组上操作,不能拷贝额外的数组。
  7. 尽量减少操作次数。
  8. Related Topics 数组 双指针
  1. public void moveZeroes(int[] nums) {
  2. /**
  3. * 存放非零元素的前驱指针,
  4. * 即:
  5. * 在[0,pre)前闭后开区间存放的都是非零元素
  6. * 在[pre,...]前闭后开区间存放的都是零元素
  7. */
  8. int pre = 0;
  9. /**
  10. * 移动指针
  11. */
  12. int cur = 0;
  13. while (cur < nums.length) {
  14. if (nums[cur] != 0) {
  15. if (pre != cur)//只有指针不相等的时候才进行交换,要不然每次相同位置也都进行交换
  16. //元素交换
  17. LeetCodeUtils.swap(nums, pre, cur);
  18. pre++;
  19. }
  20. cur++;
  21. }
  22. }

3. 移除元素

  1. 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
  2. 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
  3. 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
  4. 示例 1:
  5. 给定 nums = [3,2,2,3], val = 3,
  6. 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2
  7. 你不需要考虑数组中超出新长度后面的元素。
  8. 示例 2:
  9. 给定 nums = [0,1,2,2,3,0,4,2], val = 2,
  10. 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4
  11. 注意这五个元素可为任意顺序。
  12. 你不需要考虑数组中超出新长度后面的元素。
  13. 说明:
  14. 为什么返回数值是整数,但输出的答案是数组呢?
  15. 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
  16. 你可以想象内部操作如下:
  17. // nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
  18. int len = removeElement(nums, val);
  19. // 在函数里修改输入数组对于调用者是可见的。
  20. // 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
  21. for (int i = 0; i < len; i++) {
  22. print(nums[i]);
  23. }
  24. Related Topics 数组 双指针
  1. public int removeElement(int[] nums, int val) {
  2. int pre = 0;
  3. for (int i = 0; i < nums.length; i++) {
  4. if (nums[i]!=val)
  5. nums[pre++] = nums[i];
  6. }
  7. return pre;
  8. }

4. 删除排序数组中的重复项

  1. 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
  2. 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
  3. 示例 1:
  4. 给定数组 nums = [1,1,2],
  5. 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2
  6. 你不需要考虑数组中超出新长度后面的元素。
  7. 示例 2:
  8. 给定 nums = [0,0,1,1,1,2,2,3,3,4],
  9. 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4
  10. 你不需要考虑数组中超出新长度后面的元素。
  11. 说明:
  12. 为什么返回数值是整数,但输出的答案是数组呢?
  13. 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
  14. 你可以想象内部操作如下:
  15. // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
  16. int len = removeDuplicates(nums);
  17. // 在函数里修改输入数组对于调用者是可见的。
  18. // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
  19. for (int i = 0; i < len; i++) {
  20. print(nums[i]);
  21. }
  22. Related Topics 数组 双指针
  1. public int removeDuplicates(int[] nums) {
  2. /**
  3. * 前 [0,pre) 个全为不重复元素
  4. */
  5. int pre = 0;
  6. for (int i = 0; i < nums.length; i++) {
  7. if (nums[pre] < nums[i])
  8. nums[++pre] = nums[i];
  9. }
  10. return pre + 1;
  11. }

5. 删除排序数组中的重复项 II

  1. 给定一个增序排列数组 nums ,你需要在 原地 删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
  2. 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
  3. 说明:
  4. 为什么返回数值是整数,但输出的答案是数组呢?
  5. 请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
  6. 你可以想象内部操作如下:
  7. // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
  8. int len = removeDuplicates(nums);
  9. // 在函数里修改输入数组对于调用者是可见的。
  10. // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
  11. for (int i = 0; i < len; i++) {
  12. print(nums[i]);
  13. }
  14. 示例 1
  15. 输入:nums = [1,1,1,2,2,3]
  16. 输出:5, nums = [1,1,2,2,3]
  17. 解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 你不需要考虑数组中超出新长度后面的元素。
  18. 示例 2
  19. 输入:nums = [0,0,1,1,1,1,2,3,3]
  20. 输出:7, nums = [0,0,1,1,2,3,3]
  21. 解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 你不需要考虑数组中超出新长度后面
  22. 的元素。
  23. 提示:
  24. 0 <= nums.length <= 3 * 104
  25. -104 <= nums[i] <= 104
  26. nums 按递增顺序排列
  27. Related Topics 数组 双指针
  1. public int removeDuplicates(int[] nums) {
  2. /**
  3. * [0,pre) 范围是每个最多出现两次的元素
  4. */
  5. int pre = 0;
  6. //标记是否为第一次相同
  7. Boolean isFirst = true;
  8. for (int i = 1; i < nums.length; i++) {
  9. /**
  10. * 第一次相同,将isFirst设置为false
  11. * 并放入 [0,pre)
  12. */
  13. if (nums[pre] == nums[i] && isFirst) {
  14. nums[++pre] = nums[i];
  15. isFirst = false;
  16. } else if (nums[pre] < nums[i]) {//不同,就也放入 [0,pre),并将标记 isFirst设置为true
  17. nums[++pre] = nums[i];
  18. isFirst = true;
  19. }
  20. }
  21. return pre + 1;
  22. }

6. 颜色分类

  1. 给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
  2. 此题中,我们使用整数 0 1 2 分别表示红色、白色和蓝色。
  3. 注意:
  4. 不能使用代码库中的排序函数来解决这道题。
  5. 示例:
  6. 输入: [2,0,2,1,1,0]
  7. 输出: [0,0,1,1,2,2]
  8. 进阶:
  9. 一个直观的解决方案是使用计数排序的两趟扫描算法。
  10. 首先,迭代计算出01 2 元素的个数,然后按照012的排序,重写当前数组。
  11. 你能想出一个仅使用常数空间的一趟扫描算法吗?
  12. Related Topics 排序 数组 双指针
  1. public void sortColors(int[] nums) {
  2. /**
  3. * [0,left)存放0
  4. */
  5. int left = 0;
  6. /**
  7. * (right,nums.length]存放2
  8. */
  9. int right = nums.length - 1;
  10. for (int i = 0; i <= right; ) {
  11. //首先判断当前元素是否为2,如果是
  12. //就将当前元素交换到末尾
  13. if (nums[i] == 2) {
  14. swap(nums, i, right--);
  15. }
  16. /**
  17. * 接下来的操作就类似于 “移动零”操作;只不过是将0移动到前面
  18. * 将0移动到前面,将1移动到后面
  19. * 即:当前元素是 1 的时候向前移动
  20. * 当前元素是 0 的时候,将当前元素
  21. */
  22. if (nums[i] == 1) {
  23. i++;
  24. } else if (nums[i] == 0) {
  25. swap(nums, left++, i++);
  26. }
  27. }
  28. }

7. 合并两个有序数组

  1. 给你两个有序整数数组 nums1 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
  2. 说明:
  3. 初始化 nums1 nums2 的元素数量分别为 m n
  4. 你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
  5. 示例:
  6. 输入:
  7. nums1 = [1,2,3,0,0,0], m = 3
  8. nums2 = [2,5,6], n = 3
  9. 输出:[1,2,2,3,5,6]
  10. 提示:
  11. -10^9 <= nums1[i], nums2[i] <= 10^9
  12. nums1.length == m + n
  13. nums2.length == n
  14. Related Topics 数组 双指针
  1. public void merge(int[] nums1, int m, int[] nums2, int n) {
  2. //题目说nums1 有足够的空间(nums1.length == m + n)来保存 nums2 中的元素,相当于自带了一个空数组
  3. int l = m - 1;//第一个元素元素指针
  4. int r = n - 1;//第二个数组元素指针
  5. int i = m + n - 1;
  6. while (r >= 0 && l >= 0) {
  7. if (nums1[l] >= nums2[r]) {
  8. nums1[i] = nums1[l--];
  9. } else {
  10. nums1[i] = nums2[r--];
  11. }
  12. i--;
  13. }
  14. while (r >= 0) {
  15. nums1[i--] = nums2[r--];
  16. }
  17. }

8. 数组中的第K个最大元素

  1. 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
  2. 示例 1:
  3. 输入: [3,2,1,5,6,4] k = 2
  4. 输出: 5
  5. 示例 2:
  6. 输入: [3,2,3,1,2,4,5,5,6] k = 4
  7. 输出: 4
  8. 说明:
  9. 你可以假设 k 总是有效的,且 1 k 数组的长度。
  10. Related Topics 分治算法
  1. public int findKthLargest(int[] nums, int k) {
  2. //维护一个 k 大小的优先队列便可
  3. PriorityQueue<Integer> heap = new PriorityQueue<Integer>();
  4. for (int num : nums) {
  5. if (heap.size() < k)
  6. heap.add(num);
  7. else if (heap.peek() < num) {
  8. heap.poll();
  9. heap.add(num);
  10. }
  11. }
  12. return heap.peek();
  13. }

9. 两数之和 II - 输入有序数组

  1. 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
  2. 函数应该返回这两个下标值 index1 index2,其中 index1 必须小于 index2
  3. 说明:
  4. 返回的下标值(index1 index2)不是从零开始的。
  5. 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
  6. 示例:
  7. 输入: numbers = [2, 7, 11, 15], target = 9
  8. 输出: [1,2]
  9. 解释: 2 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2
  10. Related Topics 数组 双指针 二分查找
  1. public int[] twoSum(int[] numbers, int target) {
  2. HashMap<Integer, Integer> map = new HashMap<>();
  3. for (int i = 0; i < numbers.length; i++) {
  4. if (map.containsKey(target - numbers[i]))
  5. return new int[]{map.get(target - numbers[i]) + 1, i + 1};
  6. else
  7. map.put(numbers[i], i);
  8. }
  9. return new int[]{};
  10. }

10. 验证回文串

  1. 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
  2. 说明:本题中,我们将空字符串定义为有效的回文串。
  3. 示例 1:
  4. 输入: "A man, a plan, a canal: Panama"
  5. 输出: true
  6. 示例 2:
  7. 输入: "race a car"
  8. 输出: false
  9. Related Topics 双指针 字符串

11. 反转字符串中的元音字母

  1. 编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
  2. 示例 1
  3. 输入:"hello"
  4. 输出:"holle"
  5. 示例 2
  6. 输入:"leetcode"
  7. 输出:"leotcede"
  8. 提示:
  9. 元音字母不包含字母 "y"
  10. Related Topics 双指针 字符串
  1. public String reverseVowels(String s) {
  2. if (s.length() <= 0)
  3. return "";
  4. HashSet<Character> set = new HashSet<>(Arrays.asList('a', 'i', 'o', 'u', 'e', 'A', 'I', 'O', 'U', 'E'));
  5. char[] c = s.toCharArray();
  6. int l = 0, r = s.length() - 1;
  7. while (l < r) {
  8. while (l < r && !set.contains(c[l])) {
  9. l++;
  10. }
  11. while (l < r && !set.contains(c[r])) {
  12. r--;
  13. }
  14. if (l < r) {
  15. char temp = c[l];
  16. c[l++] = c[r];
  17. c[r--] = temp;
  18. }
  19. }
  20. return new String(c);
  21. }