一文通数据结构与算法之——数组+常见题型与解题策略+Leetcode经典题

Posted 尚墨1111

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一文通数据结构与算法之——数组+常见题型与解题策略+Leetcode经典题相关的知识,希望对你有一定的参考价值。

2 数组

数组是一种基础数据结构,可以用来处理常见的排序和二分搜索问题,典型的处理技巧包括对撞指针、滑动窗口等,数组是数据结构中的基本模块之一。因为字符串是由字符数组形成的,所以二者是相似的。大多数面试问题都属于这个范畴。

数组之中常和双指针、二分查找、排序算法、字符串、矩阵相结合,以及分治算法

2.1 常见题型及解题策略

剑指offer 数组(共14道题目):

【剑指 Offer】12、矩阵中的路径

【剑指 Offer】66、构建乘积数组

27、移除元素

26、删除有序数组中的重复项

80、删除有序数组中的重复项 II

75、颜色分类(双指针)


2.2 字符串操作基础

字符串的带参构造函数,实现传入char[]

//String(char[] ch)
new String(ch);

HashSet的带参构造函数

//HashSet(Collection<? extends E> c) 构造一个包含指定 collection 中的元素的新 set。
new HashSet<>(Arrays.asList('a','e','i','o','u','A','E','I','O','U'));
//Arrays.asList(T... a) 返回一个受指定数组支持的固定大小的 List<T>

Character数组的操作

if (Character.isLetterOrDigit(ch)) {
      list.append(Character.toLowerCase(ch));
}

在字符数组中++操作的灵活运用

nums[i++] = a;//将nums[i] = a,并且i++

防止覆盖的数组后移操作

//从前往后挪的操作会导致数据的覆盖
for(int i = left;i<nums.length;i++){
    nums[i+1] = nums[i];//nums[1,2,2,3,0,0]——>{1,2,2,2,2,2}
}

int last = m+n-1;
while(j>=0){
    nums1[last--] = nums2[j--];
}

Arrays.copyOf(),实现将集合转化成数组

//copyOf(int[] original, int newLength),复制指定的数组,截取或用 0 填充(如有必要),以使副本具有指定的长度
//copyOfRange(int[] original, int from, int to) ,将指定数组的指定范围复制到一个新数组。
//返回新的数组
Arrays.copyOfRange(res, 0, index+1);

ArrayList.toArray()实现将对应的集合list转化成相同数据类型大小的数组

//list中已经存储了元素
Object[] obj = list.toArray();
//不带参数的toArray()方法,是构造的一个Object数组,然后进行数据copy

Integer[] integers = list.toArray(new Integer[list.size()]);
int[][] ans = list.toArray(new int[list.size()][]);//返回转化之后的int[][]二维数组
//带参数的toArray(T[] a) 方法,根据参数数组的类型,构造了一个对应类型的,长度跟ArrayList的size一致的数组
  
 //源码
public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

Lambda表达式Arrays.sort排序操作

Arrays.sort(arrays, (a, b) -> a[0] - b[0]);//谁小谁在前
//相当于
Arrays.sort(arrays, new Comparator<int[]>() {
     @Override
     public int compare(int[] a, int[] b) {
          return a[0]-b[0];
     }
 });

2.3 删除数组元素

  • 掌握数组删除元素的直接覆盖操作
  • 双指针法

2.3.1 题库列表

27、移除元素 (快慢指针)

26、删除有序数组中的重复项 (快慢指针)

80、删除有序数组中的重复项 II

75、颜色分类(双指针,三色旗,小米笔试)

//    快慢指针移除元素
/**
     * 27.移除元素
     * 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于
     * val 的元素,并返回移除后数组的新长度。
     * @param arr
     */
public int remove(int[] arr,int val){
        int slow = 0;
        for (int fast = 0; fast < arr.length; fast++) {
            if(arr[fast]!=val){
                arr[slow] = arr[fast];
                slow++;
            }
        }
        return slow;
    }

/**
     * 26. 原地删除有序数组中的所有重复项
     * 输入:nums = [1,1,2]
     * 输出:2, nums = [1,2]
     *
     * 输入:nums = [0,0,1,1,1,2,2,3,3,4]
     * 输出:5, nums = [0,1,2,3,4]
     * @param arr
     * @return
     */
public int removeDup(int[] arr){
    int slow= 0;
    for (int fast = 1; fast < arr.length; fast++) {
        if(arr[slow]!=arr[fast]){
            arr[++slow] = arr[fast];
        }
    }
    return slow+1;
}


75、颜色分类

采用双指针:加深理解指针确定位置进行交换的操作

 public void sortColors(int[] nums) {
        int p = 0;//作为0的分割指针
        for (int i = 0; i < nums.length; ++i) {//与i++功能一致但是性能相对更好
            if(nums[i]==0){
                int temp = nums[i];
                nums[i] = nums[p];
                nums[p] = temp;
                ++p;
            }
        }
//        2.在从p开始重现交换1 和 2 的位置
        for (int i = p; i < nums.length; ++i) {
            if(nums[i]==1){
                int temp  = nums[i];
                nums[i] = nums[p];
                nums[p] = temp;
                ++p;
            }
        }

    }

2.4 双指针技巧

2.4.1 题库列表

88. 合并两个有序数组如何将数组所有元素整体后移,防止数组覆盖?

167. 两数之和 II - 输入有序数组(有序数列的首尾双指针)

125. 验证回文串

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

11. 盛最多水的容器经典题目

209. 长度最小的子数组滑动窗口

88 、合并两个有序数组

//逆向双指针解决合并两个排序数组
 public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m-1;
        int j = n-1;
        int last = m+n-1;
        while(i>=0 && j>=0){
            if(nums1[i]>nums2[j]){
                nums1[last--] = nums1[i--];
            }else{
                nums1[last--] = nums2[j--];
            }
        }
//        剩下的部分直接复制过去
        while(j>=0){
            nums1[last--] = nums2[j--];
        }
    }

167 、两数之和 II - 输入有序数组

//给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 
/**
     * 167. 两数之和 II - 输入有序数组
     * 递增数列,输出何为目标值的下标
     * @param numbers
     * @param target
     * @return
     */
    public int[] twoSum(int[] numbers, int target) {
        int left=0,right=numbers.length-1;
        while(left<right){
            int sum = numbers[left]+numbers[right];
            if(sum==target) {
                return new int[]{left+1,right+1};
            }else if(sum<target){
                left++;
            }else{
                right--;
            }
        }
        return null;
    }

125 、验证回文串

// "A man, a plan, a canal: Panama"——>只考虑字母和数字字符,忽略字母的大小写。
public boolean isPalindrome(String s) {
    //1.字符串预处理
        StringBuilder list = new StringBuilder();
        int length = s.length();
        for (int i = 0; i < length; i++) {
            char ch = s.charAt(i);
            if (Character.isLetterOrDigit(ch)) {
                list.append(Character.toLowerCase(ch));
            }
        }
//       2.双指针遍历是否一致
        int i = 0;
        int j = list.length()-1;
        while(i<=j){
            if(list.charAt(i)!=list.charAt(j)){
                return false;
            }else{
                i++;
                j--;
            }
        }
        return true;
    }

345 、反转字符串中的元音字母

//1.将元音字符先存起来
private final static HashSet<Character> vowel = new HashSet<>(
            Arrays.asList('a','e','i','o','u','A','E','I','O','U')
    );

public String reverseVowels(String s) {
    char[] ch = new char[s.length()];
    //1.双指针前后遍历字符串
    int left = 0;
    int right = s.length()-1;
    while(left<=right){
        char cleft = s.charAt(left);
        char cright = s.charAt(right);
        //如果是非元音字符,则直接添加到新的字符数组
        if(!vowel.contains(cleft)){
            ch[left++]=cleft;
        }else if(!vowel.contains(cright)){
            ch[right--] = cright;
        }else{
            //如果是元音字符,则交换位置放
            ch[left++] = cright;
            ch[right--] = cleft;
        }
    }
    return new String(ch);
}

11 、 盛最多水的容器

public int maxArea(int[] height) {
//        1.思路:双指针,移动小的那边
        int left = 0,right = height.length-1;
        int res = 0;
        while(left<right){
            res = height[left] < height[right] ?
                    Math.max(res, (right - left) * height[left++]):
                    Math.max(res, (right - left) * height[right--]);
        }
        return res;
    }

209 、长度最小的子数组

//我们把数组中的右指针右移,直到总和大于等于 target 为止,记录个数。然后左指针右移,直到队列中元素的和小于 target为止,记录个数。重复,直到右指针到达队尾。
public int minSubArrayLen(int target, int[] nums) {
        int i = 0,j=0,sum=0;
        int res = Integer.MAX_VALUE;
        while(j<nums.length){
            //1.右指针滑动
            sum+=nums[j++];
            while(sum>=target){
                //2.固定右指针,滑动左指针,求最小的子数组
                res = Math.min(res,j-i);
                sum-=nums[i++];
            }
        }
        return res==Integer.MAX_VALUE?0:res;
    }

2.5 数组类操作

56 、合并区间

//以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

public int[][] merge(int[][] intervals) {
//        1.创建一个集合存储答案
        List<int[]> ans = new ArrayList<>();
//        2.判空直接返回
        if (intervals == null || intervals.length == 0){
            return ans.toArray(new int[0][]);
        }
//  	3.将集合按数组一维进行排序
        Arrays.sort(intervals,(a,b)->{a[0]-b[0]});

        for (int i = 0; i < intervals.length; i++) {
            int start = intervals[i][0];
            int end = intervals[i][1];
//       4.如ans中最后一个元素的end>遍历元素的start,要进行合并操作
            if(ans.size()==0 ||ans.get(ans.size()-1)[1]<start){
                ans.add(intervals[i]);
            }else{
                ans.get(ans.size()-1)[1] = Math.max(ans.get以上是关于一文通数据结构与算法之——数组+常见题型与解题策略+Leetcode经典题的主要内容,如果未能解决你的问题,请参考以下文章

一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

一文通数据结构与算法之——回溯算法+常见题型与解题策略+Leetcode经典题

一文通数据结构与算法之——图+常见题型与解题策略+Leetcode经典题

一文通数据结构与算法之——二叉树+常见题型与解题策略+Leetcode经典题

一网打尽!二分查找解题模版与题型全面解析

Python数据结构与算法篇-- 链表的应用与常见题型