LeetCode刷题:数组

本文解析了几道经典的数组题目,包括移动零、盛最多水的容器、爬楼梯和三数之和等,提供了多种解题思路,如双指针法、动态规划等,并详细介绍了每种方法的时间和空间复杂度。

Array

练题步骤

  1. 5-10分钟:读题和思考
    • 有思路:自己开始做和写代码;
    • 不然,马上看题解!
  2. 第一遍:默写背诵、熟练
  3. 第二遍:然后开始自己写(闭卷)

移动零

283. 移动零:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

题解思路

用两个指针ij,只要nums[i]!=0,我们就交换nums[i]nums[j]

283_2.gif

class Solution {
    public void moveZeroes(int[] nums) {
        // 增强稳健性
        if (nums == null || nums.length == 0)
            return;
        //insertPos就是图示中的b
        int insertPos = 0;
        // i就是图示中的a
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                int temp = nums[j];
                nums[insertPos++] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

盛最多水的容器

11. 盛最多水的容器:给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

img

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

解题思路一:枚举

  • 枚举:left bar x, right bar y,(x-y) *height_diff
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
// 解法一:枚举法
        int maxArea = 0;
 		// 双层循环的写法
        for (int i = 0; i < height.length; i++) {
            for (int j = i + 1; j < height.length; j++) {
                int area = Math.min(height[i], height[j]) * (j - i);
                maxArea = Math.max(maxArea, area);
            }
        }
        return maxArea;

解题思路二:双指针算法

  • 关键字∶左右两边
  • 模式识别:需要移动左右两头的问题可以考虑双指针
  • 相同情况下两边距离越远越好区域受限于较短边
class Solution {
    public int maxArea(int[] height) {
        if (height.length == 0 || height == null) {
            return 0;
        }
        int left = 0;
        int right = height.length - 1;
        int maxArea = 0;

        while (left < right) {
            int tempArea = Math.min(height[left], height[right]) * (right - left);
            maxArea = Math.max(maxArea, tempArea);
            if (height[left] < height[right]) {
                ++left;
            } else {
                --right;
            }
        }
        return maxArea;
    }
}

精简写法

  • 左右边界i、j,向中间收敛:左右夹逼
class Solution {
    public int maxArea(int[] height) {
        public int maxArea ( int[] height){
            int maxArea = 0;
            for (int i = 0, j = height.length - 1; i < j; ) {
                // 取出小的那个短边
                int minHeight = height[i] < height[j] ? height[i++] : height[j--];
                // 因为这里的i,j在前面被移动过一次,宽度变小,所以要加1;
                // int area = minHeight * (j - i + 1)
                maxArea = Math.max(maxArea,minHeight * (j - i + 1));
            }
            return maxArea;
        }
    }
}

爬楼梯

70. 爬楼梯:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?**注意:**给定 n 是一个正整数。

解题思路一:斐波那契数列

如果观察数学规律,可知本题是斐波那契数列,那么用斐波那契数列的公式即可解决问题,公式如下:根据递推方程 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n - 1) + f(n - 2) f(n)=f(n1)+f(n2),我们可以写出这样的特征方程:
x 2 = x + 1 x^2=x+1 x2=x+1
求得 x 1 = 1 + 5 2 x_1=\frac{1+\sqrt{5}}{2} x1=21+5 x 2 = 1 − 5 2 x_2=\frac{1-\sqrt{5}}{2} x2=215 ,设通解为 f ( n ) = c 1 x 1 n + c 2 x 2 n f(n)=c_1x_{1}^{n} +c_2x_{2}^{n} f(n)=c1x1n+c2x2n,代入初始条件f(1)=1,f(2)=2,得 c 1 = 1 5 c_1=\frac{1}{\sqrt5} c1=5 1, c 2 = − 1 5 c_2=-\frac{1}{\sqrt5} c2=5 1,得到了这个递推数列的通项公式:
F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F_n=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n−(\frac{1-\sqrt5}{2})^n] Fn=5 1[(21+5 )n(215 )n]

  • 时间复杂度:O(logn)
class Solution {
    public int climbStairs(int n) {
        if(n<=0) return 0;
        double sqrt_5=Math.sqrt(5);
        //斐波那契表示为:f(1)=1,f(2) = 1, f(3) = 2....
        //而爬楼梯f(1) = 1, f(2) = 2,f(3) = 3
        //与斐波那契的n表示差1,所以需要将斐波那契数列的n+1
        double fib_n = Math.pow ( (1+sqrt_5)/2 , n+1)+Math.pow((1-sqrt_5)/2 , n+1);
        return (int)(fib_n/sqrt_5);
    }
}

解题思路二:动态规划

  • 找最近重复子问题

本问题其实常规解法可以分成多个子问题,爬第n阶楼梯的方法数量,等于 2 部分之和

  • 爬上 n-1阶楼梯的方法数量。因为再爬1阶就能到第n阶

  • 爬上 n-2 阶楼梯的方法数量,因为再爬2阶就能到第n阶

所以得到公式 dp[n] = dp[n-1] + dp[n-2]

  • 初始化 dp[0]=1、dp[1]=1和dp[2]=2;

时间复杂度:O(n)

image.png

class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        // dp的下标范围是[0,n]
        int[] dp = new int[n + 1];
        //0阶台阶,没有方式
        dp[0] = 0;
        //1阶台阶,只有一种方式(1)
        dp[1] = 1;
        //2阶台阶,只有两种种方式
        dp[2] = 2;
        //要遍历到第n个台阶,所以指针其实是从[0,n]
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

三数之和

15. 三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。

解题思路一:暴力求解法

  • 时间复杂度是 O ( n 3 ) O(n^3) O(n3)

大体思路如下,实际上的运行结构并不正确

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //暴力求解法
        Arrays.sort(nums);
        //结果集使用了set集合,避免了返回值重复
        Set<List<Integer>> res = new LinkedHashSet<>();
        for (int i = 0; i < nums.length - 2; i++) {
            for (int j = i + 1; j < nums.length - 1; j++) {
                for (int k = j + 1; k < nums.length; k++) {
                    if (nums[i] + nums[k] + nums[j] == 0) {
                        res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                    }
                }
            }
        }
        return  res;
    }
}

解题思路二:双指针法思路

  • 关键字:不可以包含重复
  • 模式识别:利用排序避免重复答案-降低复杂度变成twoSum
  • 利用双指针找到所有解

双指针法铺垫: 先将给定 nums 排序,复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)

具体过程:固定 3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引 (k, len(nums))两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 nums[k] + nums[i] + nums[j] == 0 的 i,j 组合:

  1. 特判,对于数组长度 n,如果数组为null或者数组长度小于 3,返回[ ]。
  2. 当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 3 个数字都大于 0 ,在此固定指针 k 之后不可能再找到结果了。
  3. 当 k > 0 且 nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。
  4. i,j 分设在数组索引 (k, len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动:
    • 当s < 0时,i += 1并跳过所有重复的nums[i];
    • 当s > 0时,j -= 1并跳过所有重复的nums[j];
    • 当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。

复杂度分析:

  • 时间复杂度 O ( N 2 ) O(N^2) O(N2):其中固定指针k循环复杂度 O(N),双指针 i,j 复杂度 O(N))。
  • 空间复杂度 O(1):指针使用常数大小的额外空间。

img

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new LinkedList<>();
        for (int k = 0; k < nums.length - 2; k++) {
            // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(nums[k] > 0) break;
            // 当k>0且 nums[k] == nums[k - 1]时即跳过此元素nums[k]
            // k > 0是为了排除初始情况
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            int i = k + 1;
            int j = nums.length - 1;
            while (i < j) {
                int sum = nums[k] + nums[i] + nums[j];
                if (sum < 0) {
                    //当s < 0时,i += 1并跳过所有重复的nums[i];
                    while (i < j && nums[i] == nums[++i]) ;
                } else if (sum > 0) {
                    //当s > 0时,j -= 1并跳过所有重复的nums[j];
                    while (i < j && nums[j] == nums[--j]) ;
                } else {
                    //当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。
                    res.add(Arrays.asList(nums[k], nums[i], nums[j]));
                    while (i < j && nums[i] == nums[++i]) ;
                    while (i < j && nums[j] == nums[--j]) ;
                }
            }

        }
        return res;
    }
}

第三课 数组、链表、跳表-Array

练题步骤

  1. 5-10分钟:读题和思考
    • 有思路:自己开始做和写代码;
    • 不然,马上看题解!
  2. 第一遍:默写背诵、熟练
  3. 第二遍:然后开始自己写(闭卷)

移动零

283. 移动零:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

题解思路

用两个指针ij,只要nums[i]!=0,我们就交换nums[i]nums[j]

283_2.gif

class Solution {
    public void moveZeroes(int[] nums) {
        // 增强稳健性
        if (nums == null || nums.length == 0)
            return;
        //insertPos就是图示中的b
        int insertPos = 0;
        // i就是图示中的a
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                int temp = nums[j];
                nums[insertPos++] = nums[i];
                nums[i] = temp;
            }
        }
    }
}

盛最多水的容器

11. 盛最多水的容器:给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

img

图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

解题思路一:枚举

  • 枚举:left bar x, right bar y,(x-y) *height_diff
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
// 解法一:枚举法
        int maxArea = 0;
 		// 双层循环的写法
        for (int i = 0; i < height.length; i++) {
            for (int j = i + 1; j < height.length; j++) {
                int area = Math.min(height[i], height[j]) * (j - i);
                maxArea = Math.max(maxArea, area);
            }
        }
        return maxArea;

解题思路二:双指针算法

  • 关键字∶左右两边
  • 模式识别:需要移动左右两头的问题可以考虑双指针
  • 相同情况下两边距离越远越好区域受限于较短边
class Solution {
    public int maxArea(int[] height) {
        if (height.length == 0 || height == null) {
            return 0;
        }
        int left = 0;
        int right = height.length - 1;
        int maxArea = 0;

        while (left < right) {
            int tempArea = Math.min(height[left], height[right]) * (right - left);
            maxArea = Math.max(maxArea, tempArea);
            if (height[left] < height[right]) {
                ++left;
            } else {
                --right;
            }
        }
        return maxArea;
    }
}

精简写法

  • 左右边界i、j,向中间收敛:左右夹逼
class Solution {
    public int maxArea(int[] height) {
        public int maxArea ( int[] height){
            int maxArea = 0;
            for (int i = 0, j = height.length - 1; i < j; ) {
                // 取出小的那个短边
                int minHeight = height[i] < height[j] ? height[i++] : height[j--];
                // 因为这里的i,j在前面被移动过一次,宽度变小,所以要加1;
                // int area = minHeight * (j - i + 1)
                maxArea = Math.max(maxArea,minHeight * (j - i + 1));
            }
            return maxArea;
        }
    }
}

爬楼梯

70. 爬楼梯:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?**注意:**给定 n 是一个正整数。

解题思路一:斐波那契数列

如果观察数学规律,可知本题是斐波那契数列,那么用斐波那契数列的公式即可解决问题,公式如下:根据递推方程 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n - 1) + f(n - 2) f(n)=f(n1)+f(n2),我们可以写出这样的特征方程:
x 2 = x + 1 x^2=x+1 x2=x+1
求得 x 1 = 1 + 5 2 x_1=\frac{1+\sqrt{5}}{2} x1=21+5 x 2 = 1 − 5 2 x_2=\frac{1-\sqrt{5}}{2} x2=215 ,设通解为 f ( n ) = c 1 x 1 n + c 2 x 2 n f(n)=c_1x_{1}^{n} +c_2x_{2}^{n} f(n)=c1x1n+c2x2n,代入初始条件f(1)=1,f(2)=2,得 c 1 = 1 5 c_1=\frac{1}{\sqrt5} c1=5 1, c 2 = − 1 5 c_2=-\frac{1}{\sqrt5} c2=5 1,得到了这个递推数列的通项公式:
F n = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] F_n=\frac{1}{\sqrt5}[(\frac{1+\sqrt5}{2})^n−(\frac{1-\sqrt5}{2})^n] Fn=5 1[(21+5 )n(215 )n]

  • 时间复杂度:O(logn)
class Solution {
    public int climbStairs(int n) {
        if(n<=0) return 0;
        double sqrt_5=Math.sqrt(5);
        //斐波那契表示为:f(1)=1,f(2) = 1, f(3) = 2....
        //而爬楼梯f(1) = 1, f(2) = 2,f(3) = 3
        //与斐波那契的n表示差1,所以需要将斐波那契数列的n+1
        double fib_n = Math.pow ( (1+sqrt_5)/2 , n+1)+Math.pow((1-sqrt_5)/2 , n+1);
        return (int)(fib_n/sqrt_5);
    }
}

解题思路二:动态规划

  • 找最近重复子问题

本问题其实常规解法可以分成多个子问题,爬第n阶楼梯的方法数量,等于 2 部分之和

  • 爬上 n-1阶楼梯的方法数量。因为再爬1阶就能到第n阶

  • 爬上 n-2 阶楼梯的方法数量,因为再爬2阶就能到第n阶

所以得到公式 dp[n] = dp[n-1] + dp[n-2]

  • 初始化 dp[0]=1、dp[1]=1和dp[2]=2;

时间复杂度:O(n)

image.png

class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        // dp的下标范围是[0,n]
        int[] dp = new int[n + 1];
        //0阶台阶,没有方式
        dp[0] = 0;
        //1阶台阶,只有一种方式(1)
        dp[1] = 1;
        //2阶台阶,只有两种种方式
        dp[2] = 2;
        //要遍历到第n个台阶,所以指针其实是从[0,n]
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

三数之和

15. 三数之和:给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。注意:答案中不可以包含重复的三元组。

解题思路一:暴力求解法

  • 时间复杂度是 O ( n 3 ) O(n^3) O(n3)

大体思路如下,实际上的运行结构并不正确

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        //暴力求解法
        Arrays.sort(nums);
        //结果集使用了set集合,避免了返回值重复
        Set<List<Integer>> res = new LinkedHashSet<>();
        for (int i = 0; i < nums.length - 2; i++) {
            for (int j = i + 1; j < nums.length - 1; j++) {
                for (int k = j + 1; k < nums.length; k++) {
                    if (nums[i] + nums[k] + nums[j] == 0) {
                        res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                    }
                }
            }
        }
        return  res;
    }
}

解题思路二:双指针法思路

  • 关键字:不可以包含重复
  • 模式识别:利用排序避免重复答案-降低复杂度变成twoSum
  • 利用双指针找到所有解

双指针法铺垫: 先将给定 nums 排序,复杂度为 O ( N l o g N ) O(NlogN) O(NlogN)

具体过程:固定 3 个指针中最左(最小)数字的指针 k,双指针 i,j 分设在数组索引 (k, len(nums))两端,通过双指针交替向中间移动,记录对于每个固定指针 k 的所有满足 nums[k] + nums[i] + nums[j] == 0 的 i,j 组合:

  1. 特判,对于数组长度 n,如果数组为null或者数组长度小于 3,返回[ ]。
  2. 当 nums[k] > 0 时直接break跳出:因为 nums[j] >= nums[i] >= nums[k] > 0,即 3 个数字都大于 0 ,在此固定指针 k 之后不可能再找到结果了。
  3. 当 k > 0 且 nums[k] == nums[k - 1]时即跳过此元素nums[k]:因为已经将 nums[k - 1] 的所有组合加入到结果中,本次双指针搜索只会得到重复组合。
  4. i,j 分设在数组索引 (k, len(nums)) 两端,当i < j时循环计算s = nums[k] + nums[i] + nums[j],并按照以下规则执行双指针移动:
    • 当s < 0时,i += 1并跳过所有重复的nums[i];
    • 当s > 0时,j -= 1并跳过所有重复的nums[j];
    • 当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。

复杂度分析:

  • 时间复杂度 O ( N 2 ) O(N^2) O(N2):其中固定指针k循环复杂度 O(N),双指针 i,j 复杂度 O(N))。
  • 空间复杂度 O(1):指针使用常数大小的额外空间。

img

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new LinkedList<>();
        for (int k = 0; k < nums.length - 2; k++) {
            // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(nums[k] > 0) break;
            // 当k>0且 nums[k] == nums[k - 1]时即跳过此元素nums[k]
            // k > 0是为了排除初始情况
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
            int i = k + 1;
            int j = nums.length - 1;
            while (i < j) {
                int sum = nums[k] + nums[i] + nums[j];
                if (sum < 0) {
                    //当s < 0时,i += 1并跳过所有重复的nums[i];
                    while (i < j && nums[i] == nums[++i]) ;
                } else if (sum > 0) {
                    //当s > 0时,j -= 1并跳过所有重复的nums[j];
                    while (i < j && nums[j] == nums[--j]) ;
                } else {
                    //当s == 0时,记录组合[k, i, j]至res,执行i += 1和j -= 1并跳过所有重复的nums[i]和nums[j],防止记录到重复组合。
                    res.add(Arrays.asList(nums[k], nums[i], nums[j]));
                    while (i < j && nums[i] == nums[++i]) ;
                    while (i < j && nums[j] == nums[--j]) ;
                }
            }

        }
        return res;
    }
}
<think>首先,用户的问是:“我想获取使用Python语言LeetCode数组相关目的指南 请问LeetCode Python数组指南”。这基于之前的引用内容,这些引用是关于LeetCode数组相关目的经验分享。 引用总结: - 引用[1]:强调了学习数组基础知识和Python方法,分析数学规律重要。 - 引用[2]:分享个人经历,练习代码水平。 - 引用[3]:LeetCode指南,提到不需要自己写输入输出,示例了类和方法。 - 引用[4]:具体解法,如双指针法去除元素。 - 引用[5]:滑动窗口解法。 用户的需求是获取一个指南,专注于使用PythonLeetCode数组目的指南。 我的回答需要: - 结构化清晰,逐步解决问。 - 使用中文。 - 确保LaTeX语法正确:行内数学用$...$,独立公式用$$...$$单独成段。 - 生成相关问。 - 在引用段落末尾添加引用标识如[^1]。 回答结构: 1. **介绍**:简要介绍LeetCode数组目的重要性和Python的优势。 2. **基础知识**:回顾数组基础和在Python中的表示。 3. **常见问类型**:列出数组相关的常见目类型。 4. **解策略**:分享通用解方法,如双指针、滑动窗口等,基于引用。 5. **Python实现技巧**:包括如何写Solution类。 6. **练习建议**:如何有效。 7. **相关问**:生成相关问。 在回答中,自然地引用给定的引用。例如: - 引用[1]提到分析数学规律重要。 - 引用[4]展示双指针法。 - 引用[5]展示滑动窗口。 确保回答真实可靠,基于标准知识。 最终生成相关问。 完整回答大纲: 1. **引言**:解释数组LeetCode中的重要性,Python作为语言的便利性。 2. **数组基础知识**: - 什么是数组? - Python中数组的表示(列表)。 - 基本操作:增删改查。 3. **解方法概述**: - 分析问模式。 - 常见算法:双指针、滑动窗口、哈希表等。 - 代码结构:LeetCode的Solution类。 4. **具体示例**: - 使用引用[4]的双指针法去除元素。 - 使用引用[5]的滑动窗口求最小子数组。 5. **策略**: - 从简单开始。 - 分析时间和空间复杂度。 - 引用[1]强调积累解思路。 6. **结论**:鼓励练习。 7. **相关问**:生成几个相关问。 生成相关问示例: 1. 如何优化数组目的时间复杂度? 2. Python中处理数组的常用库有哪些? 3. 如何调试LeetCode数组目的代码? </think>### LeetCode Python数组指南 使用PythonLeetCode数组目是提升算法和编程能力的有效方法。数组LeetCode中最基础的数据结构之一,涉及高频型如元素操作、子数组等。基于您的引用内容,我将结合实战经验,提供一个结构化指南。整个过程分为基础知识梳理、解策略、Python实现技巧和高效建议四部分,确保您能逐步上手。所有数学表达式均使用LaTeX格式规范:行内公式如$O(n)$,独立公式单独成段。 #### 1. **数组基础知识与Python表示** 数组在Python中通常用列表(`list`)表示,支持动态增删改查。关键操作包括: - **增删改查**:引用[1]强调学习数组基础操作(如添加元素`append()`、删除元素`pop()`)是入门关键[^1]。例如,删除元素的时间复杂度为$O(n)$,因为需要移动后续元素。 - **数学规律分析**:数组往往隐藏数学模式,如求和、排序或位移规律。例如,在查找问中,分析下标关系(如$i$和$j$满足$i + j = \text{target}$)能简化解法[^1]。 #### 2. **常见数组目类型与解策略** LeetCode数组可分为几类,核心是识别问模式并应用高效算法: - **元素操作类**:如去重、删除指定值。引用[4]演示了双指针法:使用左指针构建新数组,右指针遍历原数组,时间复杂度$O(n)$,空间复杂度$O(1)$[^4]。 示例解法(去除元素val): ```python class Solution: def removeElement(self, nums: List[int], val: int) -> int: left = 0 # 新数组索引 for right in range(len(nums)): # 遍历旧数组 if nums[right] != val: # 非删除元素 nums[left] = nums[right] # 赋值给新数组 left += 1 return left # 新数组长度 ``` - **子数组**:如求最小子数组长度满足和≥target。引用[5]使用滑动窗口:维护动态窗口`[low, high]`,通过移动指针调整和值,时间复杂度$O(n)$[^5]。窗口大小$L$的计算公式为: $$ L = \text{high} - \text{low} + 1 $$ - **搜索与排序类**:如两数之和或有序数组处理。引用[3]指出LeetCode只需实现Solution类的方法(如`def twoSum(self, nums: List[int], target: int) -> List[int]`),无需处理输入输出[^3]。常用哈希表(`dict`)存储索引,实现$O(1)$查找。 #### 3. **Python实现技巧与优化** - **代码结构**:所有LeetCode需定义Solution类。引用[3]示例了标准格式:方法接收`nums`(数组)和参数,返回结果[^3]。避免冗余代码,专注核心逻辑。 - **性能优化**: - 时间复杂度优先:如双指针或滑动窗口将$O(n^2)$降至$O(n)$(引用[4][^4]和[5][^5])。 - 空间优化:原地操作数组(如修改原列表而非创建新列表)。 - **调试技巧**:使用Python内置函数(如`print()`输出中间变量),或在本地IDE测试边界情况(如空数组或大输入)。 #### 4. **高效建议** - **起步方法**:引用[1]建议从简单开始,积累解思路[^1]。例如,先“Remove Element”(号27)和“Two Sum”(号1)。 - **学习路径**: 1. **基础知识巩固**:复习Python列表操作(切片、推导式)。 2. **模式识别**:每类目做5-10道,总结规律(如双指针适用场景)。 3. **复杂度分析**:引用[2]提到提升代码水平,需评估时间和空间开销[^2]。 4. **社区利用**:参考GitHub仓库(如引用[2][^2])学习他人解法。 - **避免误区**:引用[4]警示“不用算法思想:容易丢饭碗”,强调算法思维重于硬编码[^4]。 #### 结论 通过以上步骤,您可系统提升数组目解决能力。Python的简洁语法(如列表推导式)加速实现,但核心在于分析数学规律和算法选择。引用[1]强调“积累一定解思路后,可以快速给出自己的解决方案”,现在就动手吧[^1]!推荐从LeetCode标签“Array”下的简单开始。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值