LeetBook-数组类算法

74 阅读6分钟

数组类算法

数组类算法 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台

移动零

解法1

双指针(快慢指针)

  1. 快慢指针初始化均指向0
  2. 快指针遍历数组
  3. 如果碰到非0的数则向慢指针所指向的位置赋值,并且慢指针自加
  4. 遍历完成后,对慢指针指向位置之后的位置赋0
class Solution {
    public void moveZeroes(int[] nums) {
        int left = 0;
        int right;
        for (right = 0; right < nums.length; right++) {
            if (nums[right] != 0) {
                nums[left] = nums[right];
                left++;
            }
        }
        for (int i = left; i < nums.length; i++) {
            nums[i] = 0;
        }
    }
}

移除元素

解法1

双指针(快慢指针)

  1. 创建两个指针
  2. 循环为原数组赋值,如果碰到快指针的值等于val,则跳过
  3. return慢指针的值
class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        int fast;
        for (fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != val) {
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
}

删除排序数组中的重复项

解法1

双指针(快慢指针)

  1. 快慢指针初始指向数组第一个元素
  2. 快指针对数组进行循环
  3. 如果碰到快慢指针所指向的元素不一致,则慢指针自加1,然后把快指针的值赋给慢指针指向的位置
  4. 返回慢指针自加1后的整数
class Solution {
    public int removeDuplicates(int[] nums) {
        int left = 0;
        int right;
        for (right = 0; right < nums.length; right++) {
            if (nums[right] != nums[left]) {
                left++;
                nums[left] = nums[right];
            }
        }
        return ++left;
    }
}

删除排序数组中的重复项Ⅱ

解法1

  1. 快慢指针
  2. fast和slow初始指向下标2(前俩数肯定不重复)
  3. fast遍历数组
  4. 判断fast指向的数字和slow指向的数字前两个数字是否相等
  5. 不相等则赋值(如果连续三个相等数,会导致slow前俩数字指向的结果相等)
  6. 返回slow
class Solution {
    public int removeDuplicates(int[] nums) {
        int slow = 2;
        int fast;
        for (fast = 2; fast < nums.length; fast++) {
            if (nums[fast] != nums[slow - 2]) {
                nums[slow++] = nums[fast];
            }
        }
        return slow;
    }
}

颜色分类

解法1

写着玩😂

class Solution {
    public void sortColors(int[] nums) {
        Arrays.sort(nums);
    }
}

解法2

  1. 遍历把0移到左边,把2移到右边
class Solution {
    public void sortColors(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                int temp = nums[i];
                nums[i] = nums[left];
                nums[left] = temp;
                left++;
            } else if (nums[i] == 2) {
                int temp = nums[i];
                nums[i] = nums[right];
                nums[right] = temp;
                right--;
                i--;
            }
            if (i >= right) {
                break;
            }
        }
    }
}

数组中的第k个最大元素

解法1

  • sort
class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
}

解法2

  1. 用一个长度为20001的数组来计数
  2. 反向寻找
class Solution {
    public int findKthLargest(int[] nums, int k) {
        int[] xxxx = new int[20001];
        for (int i : nums) {
            xxxx[i + 10000]++;
        }
        for (int i = 20000; i >= 0; i--) {
            k -= xxxx[i];
            if (k <= 0) {
                return i - 10000;
            }
        }
        return -1;
    }
}

合并两个有序数组

解法1

  1. 尾插法
  2. m和n向前遍历,大的插入nums1的最后
  3. 循环结束,将nums1和nums2剩余的数组插入nums1前面位置
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int end = nums1.length - 1;
        m -= 1;
        n -= 1;
        while (m >= 0 && n >= 0) {
            if (nums1[m] > nums2[n]) {
                nums1[end--] = nums1[m--];
            } else {
                nums1[end--] = nums2[n--];
            }
        }
        while (m >= 0) {
            nums1[end--] = nums1[m--];
        }
        while (n >= 0) {
            nums1[end--] = nums2[n--];
        }
    }
}

两数之和Ⅱ-输入有序数组

解法1

暴力循环

  1. 遍历整个数组
  2. 如果两个数相加等于target,返回下标
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int[] result = new int[2];
        for (int i = 0; i < numbers.length; i++) {
            for (int j = i + 1; j < numbers.length; j++) {
                if (numbers[i] + numbers[j] == target) {
                    result[0] = i + 1;
                    result[1] = j + 1;
                    return result;
                }
            }
        }
        return result;
    }
}

解法2

双指针

  1. 由于数组是从小到大排列的
  2. 一个指针指向数组头,零一个指针指向数组末尾,进行循环判断,两个指针指向的数的和是否等于target
    • 如果相等,则返回下标
    • 如果大于target,则后面的指针-1
    • 如果小于target,则前面的指针+1
class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int i = 0;
        int j = numbers.length - 1;
        int[] result = new int[2];
        while (i < j) {
            if (numbers[i] + numbers[j] == target) {
                result[0] = i + 1;
                result[1] = j + 1;
                return result;
            } else if (numbers[i] + numbers[j] > target) {
                j--;
            } else {
                i++;
            }
        }
        return result;
    }
}

验证回文串

解法1

  1. 字符串的replaseAll方法,正则表达式匹配替换
  2. toLowerCase方法转小写
  3. 放入插入数组
  4. 双指针分别从前后遍历
  5. 如果不相等返回false,否则返回true
class Solution {
    public boolean isPalindrome(String s) {
        s = s.replaceAll("[^a-zA-Z0-9]", "").toLowerCase();
        char[] c = s.toCharArray();
        int left = 0; 
        int right = c.length - 1;
        while (left < right) {
            if (c[left] != c[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

解法2

  1. 解法1的基础上优化
  2. 不使用replaceAll方法,使用isLetterOrDigit方法,如果碰到非数字字母跳过
  3. 如果前后不相等返回false,否则返回true
class Solution {
    public boolean isPalindrome(String s) {
        char[] c = s.toCharArray();
        int left = 0; 
        int right = c.length - 1;
        while (left < right) {
            if (!Character.isLetterOrDigit(c[left])) {
                left++;
                continue;
            }
            if (!Character.isLetterOrDigit(c[right])) {
                right--;
                continue;
            }
            if (Character.toLowerCase(c[left]) != Character.toLowerCase(c[right])) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

反转字符串中的元音字母

解法1

  1. 正向循环,将所有元音字母取出来放到一个数组
  2. 反向循环,将所有元音字母按数组顺序替换掉
  3. 返回字符串
class Solution {
    public String reverseVowels(String s) {
        char[] c = s.toCharArray();
        char[] temp = new char[c.length];
        int index = 0;
        for (int i = 0; i < c.length; i++) {
            if (c[i] == 'a' || c[i] == 'e' || c[i] == 'i' || c[i] == 'o' || c[i] == 'u' || c[i] == 'A' || c[i] == 'E' || c[i] == 'I' || c[i] == 'O' || c[i] == 'U') {
                temp[index++] = c[i];
            }
        }
        index = 0;
        for (int i = c.length - 1; i >= 0; i--) {
            if (c[i] == 'a' || c[i] == 'e' || c[i] == 'i' || c[i] == 'o' || c[i] == 'u' || c[i] == 'A' || c[i] == 'E' || c[i] == 'I' || c[i] == 'O' || c[i] == 'U') {
                c[i] = temp[index++];
            }
        }
        return new String(c);
    }
}

盛水最多的容器

解法1

  1. 能盛多少水和最短板有关
  2. 那么就固定高度为最短板的长度,向中间循环
  3. 遍历所有情况,如果遇到更多的水,就替换result记录的结果
  4. 返回result
class Solution {
    public int maxArea(int[] height) {
        int left = 0;
        int right = height.length - 1;
        int tall = 0;
        int len = 0;
        int result = 0;
        while (left < right) {
            len = right - left;
            tall = height[left] < height[right] ? height[left++] : height[right--];
            if (len * tall > result) {
                result = len * tall;
            }
        }
        return result;
    }
}

长度最小的子数组

解法1

双指针(快慢指针)

  1. 快指针遍历数组,sum跟随快指针遍历加每个元素
  2. 如果sum大于target,则快指针固定,开始向右移动慢指针
  3. 跟随慢指针的移动sum自减每个元素,当sum小于target时,切换回移动快指针
  4. 如果快慢指针之间的距离小于min的记录(min初始为一个足够大的数),则更新min
  5. 最后如果快指针移动到最后,sum也小于target,则跳出循环
  6. return结果
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int left = 0;
        int right = 0;
        int min = 99999999;
        int sum = 0;
        while (!(right == nums.length && sum < target)) {
            if (sum >= target) {
                if (right - left < min) {
                    min = right - left;
                }
                sum -= nums[left++];
            } else {
                sum += nums[right++];
            }
        }
        if (min == 99999999) {
            return 0;
        }
        return min;
    }
}