数组算法刷题指南

1.二分查找(有序数组的经典查找算法)

问题:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果 target 存在返回下标,否则返回 -1

你必须编写一个具有 O(log n) 时间复杂度的算法。

(1)Java

java 复制代码
class Solution {
    public int search(int[] nums, int target) {
        //避免过小过大
        if(target<nums[0]|| target>nums[nums.length-1]){
            return -1;
        }
        int left =0,right=nums.length-1;
        while(left<=right){
            int middle = (left+right)/2;
            if(target==nums[middle]){
                return middle;
            }else if(target>nums[middle]){
                left=middle+1;
            }else if(target<nums[middle]){
                right=middle-1;
            }
        }
        return -1;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
    let l=0, r=nums.length-1;
    while(l<=r){
        let middle = (l+r)>>1;
        if(nums[middle]==target) return middle;
        let isSmall=nums[middle]>target;
        l=isSmall?l:middle+1;
        r=isSmall?middle-1:r;
        // if(nums[middle]>target) right=middle-1;
        // if(nums[middle]<target) left=middle+1;
    }
    return -1;
};

(3)C++

cpp 复制代码
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size()-1;
        while(left<=right){
            int middle=(left+right)/2;
            if(nums[middle]==target){
                return middle;
            }else if(nums[middle]>target){
                right=middle-1;
            }else{
                left=middle+1;
            }
        }
        return -1;
    }
};

(4)Python

python 复制代码
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left,right=0,len(nums)-1
        while left<=right:
            middle=(left+right)//2
            if nums[middle]==target:
                return middle
            elif nums[middle]>target:
                right=middle-1
            else:
                left=middle+1
        return -1

1.1搜索插入位置

问题:

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

复制代码
输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

复制代码
输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

复制代码
输入: nums = [1,3,5,6], target = 7
输出: 4

(1)Java

java 复制代码
//1、左闭右闭
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left=0, right=nums.length-1;
        while(left<=right){
            // 1. 目标值等于数组中某一个元素  return mid;
            int middle=(left+right)/2;
            if(nums[middle]==target){
                return middle;
            }else if(nums[middle]>target){
                right=middle-1;
            }else{
                left=middle+1;
            }
        }
        // 2.目标值在数组所有元素之前 3.目标值插入数组中 4.目标值在数组所有元素之后 return right + 1;
        return right+1;
    }
}
//2、左闭右开
class Solution {
    public int searchInsert(int[] nums, int target) {
        int left=0, right=nums.length;
        while(left<right){
            // 1. 目标值等于数组中某一个元素  return mid;
            int middle=(left+right)/2;
            if(nums[middle]==target){
                return middle;
            }else if(nums[middle]>target){
                right=middle-1;
            }else{
                left=middle+1;
            }
        }
        // 2.目标值在数组所有元素之前 3.目标值插入数组中 4.目标值在数组所有元素之后 return right + 1;
        return right;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var searchInsert = function(nums, target) {
    let l=0,r=nums.length-1,ans=nums.length;
    while(l<=r){
        const middle = (l+r) >> 1;
        if(nums[middle]>=target){
            ans=middle;
            r=middle-1
        }else{
            l=middle+1;
        }
    }
    return ans;
};

(3)C++

cpp 复制代码
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l=0,r=nums.size()-1;
        while(l<=r){
            int middle=(l+r)/2;
            if(nums[middle]==target){
                return middle;
            }else if(nums[middle]>target){
                r=middle-1;
            }else{
                l=middle+1;
            }
        }
        return r+1;
    }
};

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        for(int i=0;i<nums.size();i++){
            if(nums[i]>=target){
                return i;
            }
        }
        return nums.size();
    }
};

(4)Python

python 复制代码
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l,r=0,len(nums)-1
        while l<=r:
            middle=(l+r)//2
            if nums[middle]==target:
                return middle
            elif nums[middle]>target:
                r=middle-1
            else :
                l=middle+1
        return r+1

1.2在排序数组中查找元素的第一个和最后一个位置

问题:

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:你可以设计并实现时间复杂度为 O(\\log n) 的算法解决此问题吗?

示例 1:

  • 输入:nums = [5,7,7,8,8,10], target = 8
  • 输出:[3,4]

示例 2:

  • 输入:nums = [5,7,7,8,8,10], target = 6
  • 输出:[-1,-1]

示例 3:

  • 输入:nums = [], target = 0
  • 输出:[-1,-1]

(1)Java

java 复制代码
class Solution {
    int[] searchRange(int[] nums, int target){
        int leftBorder=getLeftBorder(nums,target);
        int rightBorder=getRightBorder(nums,target);
        if(leftBorder==-2 || rightBorder==-2) return new int[]{-1, -1};
        if(rightBorder-leftBorder>1) return new int[]{leftBorder+1, rightBorder-1};
        return new int[]{-1, -1};
    }
    int getLeftBorder(int[]nums, int target){
        int l=0,r=nums.length-1;
        int leftBorder=-2;
        while(l<=r){
            int m=l+(r-l)/2;
            if(nums[m]>=target){
                r=m-1;
                leftBorder=r;
            }else{
                l=m+1;
            }
        }
        return leftBorder;
    }
    int getRightBorder(int[]nums, int target){
        int l=0,r=nums.length-1;
        int rightBorder=-2;
        while(l<=r){
            int m=l+(r-l)/2;
            if(nums[m]>target){
                r=m-1;
            }else{
                l=m+1;
                rightBorder=l;
            }
        }
        return rightBorder;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    const getLeftBorder = (nums,target)=>{
        let left=0,right=nums.length-1;
        let leftBorder=-2;
        while(left<=right){
            let middle=left+(right-left)//2;
            if(nums[middle]>=target){
                right=middle-1;
                leftBorder=right;
            }else {
                left=middle+1;
            }
        }
        return leftBorder;
    }
    const getRightBorder = (nums,target)=>{
        let left=0,right=nums.length-1;
        let rightBorder=-2;
        while(left<=right){
            let middle=left+(right-left)//2;
            if(nums[middle]>target){
                right=middle-1;
            }else {
                left=middle+1;
                rightBorder=left;
            }
        }
        return rightBorder;
    }

    let leftBorder = getLeftBorder(nums,target);
    let rightBorder = getRightBorder(nums,target);
    if(leftBorder==-2 || rightBorder==-2) return [-1, -1];
    if(rightBorder-leftBorder>1) return [leftBorder+1, rightBorder-1];
    return [-1, -1];
};

(3)C++

cpp 复制代码
class Solution {
    public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int leftBorder=getLeftBorder(nums,target);
        int rightBorder=getRightBorder(nums,target);
        if(leftBorder==-2||rightBorder==-2) return {-1, -1};
        if(rightBorder-leftBorder>1) return {leftBorder+1, rightBorder-1};
        return {-1, -1};
    }
    private:
    int getLeftBorder(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        int leftBorder = -2;
        while(left<=right){
            int middle=(left+right)/2;
            if(nums[middle]>=target){
                right=middle-1;
                leftBorder=right;
            }else{
                left=middle+1;
            }
        }
        return leftBorder;
    }
    private:
    int getRightBorder(vector<int>& nums, int target) {
        int left=0,right=nums.size()-1;
        int rightBorder=-2;
        while(left<=right){
            int middle=(left+right)/2;
            if(nums[middle]>target){
                right=middle-1;
            }else{
                left=middle+1;
                rightBorder=left;
            }
        }
        return rightBorder;
    }
};

(4)Python

python 复制代码
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def getRightBorder(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1
            rightBoder = -2 # 记录一下rightBorder没有被赋值的情况
            while left <= right:
                middle = left + (right-left) // 2
                if nums[middle] > target:
                    right = middle - 1
                else: # 寻找右边界,nums[middle] == target的时候更新left
                    left = middle + 1
                    rightBoder = left
    
            return rightBoder
        
        def getLeftBorder(nums:List[int], target:int) -> int:
            left, right = 0, len(nums)-1 
            leftBoder = -2 # 记录一下leftBorder没有被赋值的情况
            while left <= right:
                middle = left + (right-left) // 2
                if nums[middle] >= target: #  寻找左边界,nums[middle] == target的时候更新right
                    right = middle - 1
                    leftBoder = right
                else:
                    left = middle + 1
            return leftBoder
        leftBoder = getLeftBorder(nums, target)
        rightBoder = getRightBorder(nums, target)
        # 情况一
        if leftBoder == -2 or rightBoder == -2: return [-1, -1]
        # 情况三
        if rightBoder -leftBoder >1: return [leftBoder + 1, rightBoder - 1]
        # 情况二
        return [-1, -1]

1.3x的平方根

问题:

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意: 不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

(2)JavaScript

javascript 复制代码
/**
 * @param {number} x
 * @return {number}
 */
var mySqrt = function(x) {
    let find = (layer,left,right)=>{
        if(right-left<=1){
            return left;
        }
        let middle = (left+right)>>1;
        if(middle*middle>x){
            right=middle
        }else{
            left=middle;
        }
        return find(layer+1,left,right);
    }
    return find(0,1,x)
};

1.4有效的完全平方数

问题:

给你一个正整数 num 。如果 num 是一个完全平方数,则返回 true ,否则返回 false

完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。

不能使用任何内置的库函数,如 sqrt

java 复制代码
class Solution {
    public boolean isPerfectSquare(int num) {
        long l=0,r=num;
        while(l<r){
            long mid = l+r+1>>1;
            if(mid*mid<=num) l=mid;
            else r=mid-1;
        }
        return r*r==num;
    }
}

2.移除元素(数组元素的原地修改、双指针技巧)

问题:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例 1: 给定 nums = [3,2,2,3], val = 3, 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。 你不需要考虑数组中超出新长度后面的元素。

示例 2: 给定 nums = [0,1,2,2,3,0,4,2], val = 2, 函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

你不需要考虑数组中超出新长度后面的元素。

(1)Java

java 复制代码
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
//暴力解法:两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组
class Solution {
    public int removeElement(int[] nums, int val) {
        int size=nums.length;
        for(int i=0;i<size;i++){
            if(nums[i]==val){
                for(int j=i+1;j<size;j++){
                    nums[j-1]=nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }
}

// 时间复杂度:O(n)
// 空间复杂度:O(1)
//双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
// 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
// 慢指针:指向更新 新数组下标的位置
class Solution {
    public int removeElement(int[] nums, int val) {
        int slow=0;
        for(int fast=0;fast<nums.length;fast++){
            if(nums[fast]!=val){
                nums[slow++]=nums[fast];
            }
        }
        return slow;
    }
}

(2)JavaScript

javascript 复制代码
//暴力:
/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    let size=nums.length;
    for(let i=0;i<size;i++){
        if(nums[i]==val){
            for(let j=i+1;j<size;j++){
                nums[j-1]=nums[j];
            }
            i--;
            size--;
        }
    }
    return size;
};

//双指针
/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    let slow=0;
    for(let fast=0;fast<nums.length;fast++){
        if(nums[fast]!=val){
            nums[slow++]=nums[fast];
        }
    }
    return slow;
};

(3)C++

cpp 复制代码
// 时间复杂度:O(n^2)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size=nums.size();
        for(int i=0;i<size;i++){
            if(nums[i]==val){
                for(int j=i+1;j<size;j++){
                    nums[j-1]=nums[j];
                }
                i--;
                size--;
            }
        }
        return size;
    }
};

// 时间复杂度:O(n)
// 空间复杂度:O(1)
// 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
// 慢指针:指向更新 新数组下标的位置
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow=0;
        for(int fast=0;fast<nums.size();fast++){
            if(nums[fast]!=val){
                nums[slow++]=nums[fast];
            }
        }
        return slow;
    }
};

(4)Python

python 复制代码
//暴力
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i,l=0,len(nums)
        while i<l:
            if nums[i]==val:
                for j in range(i+1,l):
                    nums[j-1]=nums[j]
                l-=1
                i-=1
            i+=1
        return l

//双指针
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        slow=0
        fast=0
        size=len(nums)
        while fast<size:
            if nums[fast]!=val:
                nums[slow]=nums[fast]
                slow+=1
            fast+=1
        return slow

2.1 删除有序数组中的重复项

问题:

给你一个 非严格递增排列 的数组 nums ,请你**原地** 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k。去重后,返回唯一元素的数量 k

nums 的前 k 个元素应包含 排序后 的唯一数字。下标 k - 1 之后的剩余元素可以忽略。

(1)Java

java 复制代码
class Solution {
    public int removeDuplicates(int[] nums) {
        int j=0;
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=nums[j]){
                nums[++j]=nums[i];
            }
        }
        return j+1;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let j=0;
    for(let i=0;i<nums.length;i++){
        if(nums[i]!=nums[j]){
            nums[++j]=nums[i]
        }
    }
    return j+1;
};

(3)C++

cpp 复制代码
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int j=0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]!=nums[j]){
                nums[++j]=nums[i];
            }
        }
        return j+1;
    }
};

(4)Python

python 复制代码
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        j=0
        for i in range(len(nums)):
            if nums[i]!=nums[j]:
                j+=1
                nums[j]=nums[i]
        return j+1

2.2 移动零

问题:

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

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

(1)Java

java 复制代码
class Solution {
    public void moveZeroes(int[] nums) {
        int j=0;
        //统计非零,将非零赋给nums[j]
        for(int i=0;i<nums.length;i++){
            if(nums[i]!=0){
                nums[j++]=nums[i];
            }
        }
        //从 j 开始,把后面所有位置赋值为0
        for(int i=j;i<nums.length;i++){
            nums[i]=0;
        }
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function(nums) {
    let j=0;
    //统计非零,将非零赋给nums[j]
    for(let i=0;i<nums.length;i++){
        if(nums[i]!=0){
            nums[j++]=nums[i];
        }
    }
    //从 j 开始,把后面所有位置赋值为0
    for(let i=j;i<nums.length;i++){
        nums[i]=0;
    }
};

(3)C++

javascript 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int j=0;
        //统计非零,将非零赋给nums[j]
        for(int i=0;i<nums.size();i++){
            if(nums[i]!=0){
                nums[j++]=nums[i];
            }
        }
        //从 j 开始,把后面所有位置赋值为0
        for(int i=j;i<nums.size();i++){
            nums[i]=0;
        }
    }
};

(4)Python

python 复制代码
class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        j=0
        for i in range(len(nums)):
            if(nums[i]!=0):
                nums[j]=nums[i]
                j+=1
        for i in range(j,len(nums)):
            nums[i]=0
        return nums

3.有序数组的平方(数组变换 + 双指针)

问题:

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

  • 输入:nums = [-4,-1,0,3,10]
  • 输出:[0,1,9,16,100]
  • 解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]

示例 2:

  • 输入:nums = [-7,-3,2,3,11]
  • 输出:[4,9,9,49,121]

(1)Java

java 复制代码
class Solution {
    public int[] sortedSquares(int[] nums) {
        for(int i=0;i<nums.length;i++){
            nums[i]=nums[i]*nums[i];
        }
        Arrays.sort(nums);
        return nums;
    }
}


class Solution {
    public int[] sortedSquares(int[] nums) {
        int r=nums.length-1;
        int l=0;
        int[] result = new int[nums.length];
        int index=nums.length-1;
        while(l<=r){
            if(nums[l]*nums[l]>nums[r]*nums[r]){
                result[index--]=nums[l]*nums[l];
                ++l;
            }else{
                result[index--]=nums[r]*nums[r];
                --r;
            }
        }
        return result;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function(nums) {
    let n=nums.length;
    let result=new Array(n).fill(0);
    let l=0,r=n-1,i=n-1;
    while(l<=r){
        if(nums[l]*nums[l]>nums[r]*nums[r]){
            result[i--]=nums[l]*nums[l];
            ++l;
        }else{
            result[i--]=nums[r]*nums[r];
            --r
        }
    }
    return result;
};

(3)C++

cpp 复制代码
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        //暴力排序时间复杂度是 O(n + nlogn)
        for(int i=0;i<nums.size();i++){
            nums[i]*=nums[i];
        }
        sort(nums.begin(),nums.end());
        return nums;
    }
};

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        //时间复杂度O(n)
       int k=nums.size()-1;
       vector<int> result(nums.size(),0);
       for(int i=0,j=nums.size()-1;i<=j;){
        if(nums[i]*nums[i]>nums[j]*nums[j]){
            result[k--]=nums[i]*nums[i];
            i++;
        }else{
            result[k--]=nums[j]*nums[j];
            j--;
        }
       }
       return result;
    }
};

4.长度最小的子数组(滑动窗口 / 前缀和)

问题:

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

  • 输入:s = 7, nums = [2,3,1,2,4,3]
  • 输出:2
  • 解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

  • 1 <= target <= 10^9
  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^5

(1)Java

java 复制代码
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        int sum = 0; 
        int i=0;
        for(int j=0;j<nums.length;j++){
            sum+=nums[j];
            while(sum>=target){
                result=Math.min(result,j-i+1);
                sum-=nums[i++];
            }
        }
        return result==Integer.MAX_VALUE?0:result;
    }
}

(2)JavaScript

javascript 复制代码
/**
 * @param {number} target
 * @param {number[]} nums
 * @return {number}
 */
var minSubArrayLen = function(target, nums) {
    let result = Infinity;
    let sum = 0; 
    let i=0;
    for(let j=0;j<nums.length;j++){
        sum+=nums[j];
        while(sum>=target){
            result=Math.min(result,j-i+1);
            sum-=nums[i++];
        }
    }
    return result==Infinity?0:result;
};

(3)C++

cpp 复制代码
//暴力,超时了
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; 
        int subLength = 0; 
        for (int i = 0; i < nums.size(); i++) { 
            sum = 0;
            for (int j = i; j < nums.size(); j++) { 
                sum += nums[j];
                if (sum >= s) { 
                    subLength = j - i + 1;
                    result = result < subLength ? result : subLength;
                    break; 
                }
            }
        }
        return result == INT32_MAX ? 0 : result;
    }
};

//s时间复杂度(n)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; 
        int sumLength = 0; 
        int i=0;
        for(int j=0;j<nums.size();j++){
            sum+=nums[j];
            while(sum>=s){
                sumLength=j-i+1;
                result=result<sumLength?result:sumLength;
                sum-=nums[i++];
            }
        }
        return result==INT32_MAX?0:result;
    }
};

5.螺旋矩阵II(数组的二维遍历、模拟)

问题:

给定一个正整数 n,生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。

示例:

输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]

(1)Java

java 复制代码
class Solution {
    public int[][] generateMatrix(int n) {
        int[][] nums=new int[n][n];
        int startX=0,startY=0;
        int offset=1;
        int count=1;
        int loop=1;
        int i,j;//j表示列,i表示行
        while(loop<=n/2){
            //顶部
            // 左闭右开,所以判断循环结束时, j 不能等于 n-offset
            for(j=startY;j<n-offset;j++){
                nums[startX][j]=count++;
            }
            // 右列
            // 左闭右开,所以判断循环结束时, i 不能等于 n - offset
            for(i=startX;i<n-offset;i++){
                nums[i][j]=count++;
            }
            // 底部,从右往左
            // 左闭右开,所以判断循环结束时, j != startY
            for(;j>startY;j--){
                nums[i][j]=count++;
            }
            //左列,从下往上
            //左闭右开,所以判断循环结束时, i != startX
            for(;i>startX;i--){
                nums[i][j]=count++;
            }
            startX++;
            startY++;
            offset++;
            loop++;
        }
        if(n%2==1){
            nums[startX][startY]=count;
        }
        return nums;
    }
}

(2)Javascript

javascript 复制代码
/**
 * @param {number} n
 * @return {number[][]}
 */
var generateMatrix = function(n) {
        let nums = new Array(n).fill(0).map(() => new Array(n).fill(0));
        let startX = 0, startY = 0;  // 每一圈的起始点
        let offset = 1;
        let count = 1;  // 矩阵中需要填写的数字
        let loop = Math.floor(n/2); // 记录当前的圈数
        let mid = Math.floor(n/2);//中间位置
        let i, j; // j 代表列, i 代表行;

        while (loop--) {

            // 顶部
            // 左闭右开,所以判断循环结束时, j 不能等于 n - offset
            for (j = startY; j < n - offset; j++) {
                nums[startX][j] = count++;
            }

            // 右列
            // 左闭右开,所以判断循环结束时, i 不能等于 n - offset
            for (i = startX; i < n - offset; i++) {
                nums[i][j] = count++;
            }

            // 底部
            // 左闭右开,所以判断循环结束时, j != startY
            for (; j > startY; j--) {
                nums[i][j] = count++;
            }

            // 左列
            // 左闭右开,所以判断循环结束时, i != startX
            for (; i > startX; i--) {
                nums[i][j] = count++;
            }
            startX++;
            startY++;
            offset++;
        }
        if (n % 2 == 1) { // n 为奇数时,单独处理矩阵中心的值
            nums[mid][mid] = count;
        }
        return nums;
};

(3)C++

cpp 复制代码
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>nums(n,vector<int>(n,0));
        int startX=0,startY=0;
        int offset=1;
        int count=1;
        int loop=1;
        int i,j;//j表示列,i表示行
        while(loop<=n/2){
            //顶部
            // 左闭右开,所以判断循环结束时, j 不能等于 n-offset
            for(j=startY;j<n-offset;j++){
                nums[startX][j]=count++;
            }
            // 右列
            // 左闭右开,所以判断循环结束时, i 不能等于 n - offset
            for(i=startX;i<n-offset;i++){
                nums[i][j]=count++;
            }
            // 底部,从右往左
            // 左闭右开,所以判断循环结束时, j != startY
            for(;j>startY;j--){
                nums[i][j]=count++;
            }
            //左列,从下往上
            //左闭右开,所以判断循环结束时, i != startX
            for(;i>startX;i--){
                nums[i][j]=count++;
            }
            startX++;
            startY++;
            offset++;
            loop++;
        }
        if(n%2==1){
            nums[startX][startY]=count;
        }
        return nums;
    }
};

6.区间和(前缀和算法)

问题:

给定一个整数数组 Array,请计算该数组在每个指定区间内元素的总和。

输入描述

第一行输入为整数数组 Array 的长度 n,接下来 n 行,每行一个整数,表示数组的元素。随后的输入为需要计算总和的区间,直至文件结束。

输出描述

输出每个指定区间内元素的总和。

输入示例

复制代码
5
1
2
3
4
5
0 1
1 3

输出示例

复制代码
3
9

数据范围:

0 < n <= 100000

(1)Java

java 复制代码
import java.util.Scanner;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int n=scanner.nextInt();
        int[] vec=new int[n];
        int[] p=new int[n];

        int presum=0;
        for(int i=0;i<n;i++){
            vec[i]=scanner.nextInt();
            presum+=vec[i];
            p[i]=presum;
        }
        while(scanner.hasNextInt()){
            int a=scanner.nextInt();
            int b=scanner.nextInt();
            int sum;
            if(a==0){
                sum=p[b];
            }else{
                sum=p[b]-p[a-1];
            }
            System.out.println(sum);
        }
        scanner.close();
    }
}

(2)C++

cpp 复制代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
    int n, a, b;
    cin >> n;
    vector<int> vec(n);
    vector<int> p(n);
    int presum = 0;
    for (int i = 0; i < n; i++) {
        scanf("%d", &vec[i]);
        presum += vec[i];
        p[i] = presum;
    }

    while (~scanf("%d%d", &a, &b)) {
        int sum;
        if (a == 0) sum = p[b];
        else sum = p[b] - p[a - 1];
        printf("%d\n", sum);
    }
}

7.开发商购买土地(二维前缀和的实际应用)

在一个城市区域内,被划分成了n * m个连续的区块,每个区块都拥有不同的权值,代表着其土地价值。目前,有两家开发公司,A 公司和 B 公司,希望购买这个城市区域的土地。

现在,需要将这个城市区域的所有区块分配给 A 公司和 B 公司。

然而,由于城市规划的限制,只允许将区域按横向或纵向划分成两个子区域,而且每个子区域都必须包含一个或多个区块。

为了确保公平竞争,你需要找到一种分配方式,使得 A 公司和 B 公司各自的子区域内的土地总价值之差最小。

注意:区块不可再分。

【输入描述】

第一行输入两个正整数,代表 n 和 m。

接下来的 n 行,每行输出 m 个正整数。

输出描述

请输出一个整数,代表两个子区域内土地总价值之间的最小差距。

【输入示例】

复制代码
3 3
1 2 3
2 1 3
1 2 3

【输出示例】

0

【提示信息】

如果将区域按照如下方式划分:

复制代码
1 2 | 3
2 1 | 3
1 2 | 3

两个子区域内土地总价值之间的最小差距可以达到 0。

【数据范围】:

  • 1 <= n, m <= 100;
  • n 和 m 不同时为 1。

(1)Java

java 复制代码
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        int sum = 0;
        int[][] vec = new int[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                vec[i][j] = scanner.nextInt();
                sum += vec[i][j];
            }
        }

        int result = Integer.MAX_VALUE;
        int count = 0; // 统计遍历过的行

        // 行切分
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                count += vec[i][j];
                // 遍历到行末尾时候开始统计
                if (j == m - 1) {
                    result = Math.min(result, Math.abs(sum - 2 * count));
                }
            }
        }

        count = 0;
        // 列切分
        for (int j = 0; j < m; j++) {
            for (int i = 0; i < n; i++) {
                count += vec[i][j];
                // 遍历到列末尾时候开始统计
                if (i == n - 1) {
                    result = Math.min(result, Math.abs(sum - 2 * count));
                }
            }
        }

        System.out.println(result);
        scanner.close();
    }
}
相关推荐
江湖有缘2 小时前
基于华为openEuler系统部署Memory笔记管理工具
笔记
小陈phd2 小时前
多模态大模型学习笔记(三十三)——基于YOLOv11的安全帽佩戴检测算法
笔记·学习·yolo
雨浓YN2 小时前
OPC DA 通讯开发笔记
windows·笔记
taoqick2 小时前
rubric系列论文粗读笔记
笔记
航Hang*2 小时前
第2章:进阶Linux系统——第8节:配置与管理MariaDB服务器
linux·运维·服务器·数据库·笔记·学习·mariadb
自小吃多2 小时前
电气安全检测说明书
笔记·安全
水蓝烟雨2 小时前
LeetCode刷题笔记:合并两个有序链表(0021)
笔记·leetcode·链表
鱼鳞_2 小时前
Java学习笔记_Day23(双列集合)
java·笔记·学习
ZhiqianXia2 小时前
Pytorch 学习笔记(9): PyTorch.Compile
pytorch·笔记·学习