代码随想录训练营【数组篇】整理

注:本篇文章代码以及部分内容来源于代码随想录

C++基础知识补课

#include <iostream>

这一行代码包含了C++标准库中的输入输出流头文件iostream。它提供了输入输出操作的功能,比如cin用于输入,cout用于输出。

#include <vector>

这一行代码包含了C++标准库中的容器类vectorvector是一种动态数组,可以自动调整大小,提供了方便的操作接口。

using namespace std;

这一行代码告诉编译器我们要使用标准命名空间std。这样我们就可以直接使用标准库中的对象和函数,而不需要每次都加上std::前缀。

int search(vector<int>& nums, int target)

这是一个函数声明,定义了一个名为search的函数,该函数接受两个参数:

  • vector<int>& nums:一个引用类型的整数向量(数组)。
  • int target:一个整数目标值。

函数的返回类型是int,表示它将返回一个整数值(目标值的索引)。

vector<int> nums = {1, 3, 5, 7, 9};

这一行代码定义并初始化了一个整数向量nums,其中包含了一些有序的整数值。向量nums的内容是{1, 3, 5, 7, 9}

cout << "Index of target " << target << " is: " << index << endl;

这一行代码使用cout输出信息到控制台。具体来说,它输出了目标值target及其在数组中的索引indexendl用于换行。

关于引用:

引用类型(Reference)

在C++中,引用是一种类型,它是一个已经存在的变量的别名。通过引用,我们可以直接操作原变量,而无需复制数据。

引用的定义和使用

定义引用时使用&符号。例如:

int a = 10;
int& ref = a; // ref是a的引用

在这个例子中,refa的引用,refa指向同一个内存地址。因此,通过ref修改变量的值,会直接影响到a

在函数参数中使用引用

将参数作为引用传递给函数,可以避免复制参数数据,特别是在处理大型数据结构(如向量)时,使用引用可以提高性能。

在这两个代码片段中,主要区别在于modifyVector函数的参数是按引用传递还是按值传递。这导致了在函数调用过程中对向量的操作效果不同。

代码片段1:按引用传递

#include <iostream>
#include <vector>

using namespace std;

void modifyVector(vector<int>& vec) {
    for (int i = 0; i < vec.size(); ++i) {
        vec[i] *= 2; // 将向量中的每个元素乘以2
    }
}

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5}; // 定义一个整数向量
    modifyVector(numbers); // 通过引用传递向量
    for (int num : numbers) {
        cout << num << " "; // 输出修改后的向量元素
    }
    cout << endl;
    return 0;
}

代码片段2:按值传递

#include <iostream>
#include <vector>

using namespace std;

void modifyVector(vector<int> vec) {
    for (int i = 0; i < vec.size(); ++i) {
        vec[i] *= 2; // 将向量中的每个元素乘以2
    }
}

int main() {
    vector<int> numbers = {1, 2, 3, 4, 5}; // 定义一个整数向量
    modifyVector(numbers); // 按值传递向量
    for (int num : numbers) {
        cout << num << " "; // 输出修改后的向量元素
    }
    cout << endl;
    return 0;
}

主要区别

  1. 传递方式

    • 按引用传递(代码片段1):函数参数vector<int>& vec是一个引用。这意味着函数modifyVector直接操作传入的原始向量numbers,所有的修改都会反映到numbers中。
    • 按值传递(代码片段2):函数参数vector<int> vec是按值传递。这意味着调用modifyVector时,会创建numbers的一个副本vec,函数内的修改只影响副本,不会影响原始向量numbers
  2. 函数执行结果

    • 按引用传递(代码片段1):函数modifyVectornumbers的每个元素乘以2,修改后numbers的内容是{2, 4, 6, 8, 10}。输出结果是:2 4 6 8 10
    • 按值传递(代码片段2):函数modifyVector只修改副本vecnumbers不变。输出结果仍然是原始内容:1 2 3 4 5

代码片段1的详细执行过程(按引用传递):

  1. main函数定义并初始化numbers{1, 2, 3, 4, 5}
  2. 调用modifyVector(numbers),将numbers的引用传递给vec
  3. modifyVector函数中,对vec的每个元素乘以2,实际修改的是numbers
  4. 函数返回后,numbers的内容变为{2, 4, 6, 8, 10}
  5. main函数输出修改后的numbers2 4 6 8 10

代码片段2的详细执行过程(按值传递):

  1. main函数定义并初始化numbers{1, 2, 3, 4, 5}
  2. 调用modifyVector(numbers),将numbers的副本传递给vec
  3. modifyVector函数中,对vec的每个元素乘以2,但这只影响副本vec,不影响原始向量numbers
  4. 函数返回后,numbers的内容仍然是{1, 2, 3, 4, 5}
  5. main函数输出原始的numbers1 2 3 4 5

总结

  • 按引用传递:函数直接操作原始数据,提高效率并使修改直接反映到原数据上。
  • 按值传递:函数操作的是数据的副本,原数据保持不变,适用于不希望函数修改原数据的情况。

选择按引用还是按值传递取决于你的需求:是否希望函数修改原数据,以及是否需要提高性能(避免不必要的数据复制)。

数组

1.二分查找法 704

力扣704

需要注意端点,左闭右闭or左闭右开?

C++

左闭右闭
// 版本一
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};
ACM模式
#include <iostream>
#include <vector>

using namespace std;

int search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1;
    while (left <= right) {
        int middle = left + ((right - left) / 2);
        if (nums[middle] > target) {
            right = middle - 1;
        } else if (nums[middle] < target) {
            left = middle + 1;
        } else {
            return middle;
        }
    }
    return -1;
}

int main() {
    vector<int> nums = {1, 3, 5, 7, 9}; // 定义并初始化一个整数向量
    int target = 7; // 定义目标值
    int index = search(nums, target); // 调用search函数查找目标值的索引
    cout << "Index of target " << target << " is: " << index << endl; // 输出结果
    return 0;
}

ACM模式用户输入
//让用户输入数组和目标值,并在同一行以逗号分隔.用户输入类似于[1,3,5,7,9],7
#include <iostream>
#include <vector>
#include <sstream>

using namespace std;

int search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1;
    while (left <= right) {
        int middle = left + ((right - left) / 2);
        if (nums[middle] > target) {
            right = middle - 1;
        } else if (nums[middle] < target) {
            left = middle + 1;
        } else {
            return middle;
        }
    }
    return -1;
}

int main() {
    string input;
    cout << "请输入数组和目标值(格式为[1,3,5,7,9],7):";
    getline(cin, input);

    // 移除输入中的方括号
    input.erase(remove(input.begin(), input.end(), '['), input.end());
    input.erase(remove(input.begin(), input.end(), ']'), input.end());

    stringstream ss(input);
    string temp;
    vector<int> nums;
    int target;

    // 解析输入字符串
    while (getline(ss, temp, ',')) {
        if (ss.peek() == EOF) {
            target = stoi(temp); // 最后一个值是目标值
        } else {
            nums.push_back(stoi(temp)); // 将每个值添加到数组中
        }
    }

    int index = search(nums, target); // 调用search函数查找目标值的索引
    cout << "目标值 " << target << " 的索引是: " << index << endl; // 输出结果

    return 0;
}
左闭右开
// 版本二
//时间复杂度:O(log n)
//空间复杂度:O(1)
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

Python

左闭右闭
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1  # 定义target在左闭右闭的区间里,[left, right]

        while left <= right:
            middle = left + (right - left) // 2
            
            if nums[middle] > target:
                right = middle - 1  # target在左区间,所以[left, middle - 1]
            elif nums[middle] < target:
                left = middle + 1  # target在右区间,所以[middle + 1, right]
            else:
                return middle  # 数组中找到目标值,直接返回下标
        return -1  # 未找到目标值
ACM模式用户输入
//接受用户输入,输入格式为[1,3,5,7,9],7
from typing import List

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums) - 1  # 定义target在左闭右闭的区间里,[left, right]

        while left <= right:
            middle = left + (right - left) // 2
            
            if nums[middle] > target:
                right = middle - 1  # target在左区间,所以[left, middle - 1]
            elif nums[middle] < target:
                left = middle + 1  # target在右区间,所以[middle + 1, right]
            else:
                return middle  # 数组中找到目标值,直接返回下标
        return -1  # 未找到目标值

def parse_input(input_str: str):
    # 去掉输入字符串中的方括号
    input_str = input_str.replace('[', '').replace(']', '')
    # 按逗号分割输入字符串
    parts = input_str.split(',')
    # 将前面部分解析为整数列表
    nums = list(map(int, parts[:-1]))
    # 将最后一个部分解析为目标值
    target = int(parts[-1])
    return nums, target

# 或者这样写:
"""
def parse_input(input_str: str):
    # 先按']'分隔
    parts = input_str.split(']')  # parts = ['[1,3,5,7,9', ',7']
    # 去掉第一个部分的左边的'['
    nums_str = parts[0].lstrip('[') # nums_str = '1,3,5,7,9'
    # 将字符串转换为整数列表
    nums = list(map(int, nums_str.split(','))) # nums = [1, 3, 5, 7, 9]
    # 去掉第二个部分的逗号,得到目标值
    target = int(parts[1].lstrip(',')) # target = 7
    return nums, target
"""

if __name__ == "__main__":
    input_str = input("请输入数组和目标值(格式为[1,3,5,7,9],7):")
    nums, target = parse_input(input_str)
    
    solution = Solution()
    index = solution.search(nums, target)
    print(f"目标值 {target} 的索引是: {index}")

左闭右开
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        left, right = 0, len(nums)  # 定义target在左闭右开的区间里,即:[left, right)

        while left < right:  # 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            middle = left + (right - left) // 2

            if nums[middle] > target:
                right = middle  # target 在左区间,在[left, middle)中
            elif nums[middle] < target:
                left = middle + 1  # target 在右区间,在[middle + 1, right)中
            else:
                return middle  # 数组中找到目标值,直接返回下标
        return -1  # 未找到目标值

2.移除元素 27

力扣27

C++

暴力解法
// 时间复杂度: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--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

    }
};
双指针法

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};
ACM模式用户输入
//接受用户输入,输入格式类似于[1,2,2,3],2
#include <iostream>
#include <vector>
#include <sstream>

using namespace std;

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

vector<int> parseInput(const string& input_str, int& val) {
    // 去掉输入字符串中的方括号
    string modified_input = input_str;
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), '['), modified_input.end());
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), ']'), modified_input.end());

    // 按逗号分割输入字符串
    stringstream ss(modified_input);
    string temp;
    vector<int> nums;
    
    while (getline(ss, temp, ',')) {
        nums.push_back(stoi(temp));
    }

    // 最后一个部分解析为目标值
    val = nums.back();
    nums.pop_back(); // 删除最后一个元素,因为它是目标值

    return nums;
}

int main() {
    string input_str;
    cout << "请输入数组和目标值(格式为[1,2,2,3],2):";
    getline(cin, input_str);
    
    int val;
    vector<int> nums = parseInput(input_str, val);
    
    Solution solution;
    int new_length = solution.removeElement(nums, val);
    
    cout << "新的数组长度: " << new_length << endl;
    cout << "修改后的数组: ";
    for (int i = 0; i < new_length; ++i) {
        cout << nums[i] << " ";
    }
    cout << endl;
    
    return 0;
}

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:
        # 快慢指针
        fast = 0  # 快指针
        slow = 0  # 慢指针
        size = len(nums)
        while fast < size:  # 不加等于是因为,a = size 时,nums[a] 会越界
            # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
ACM模式用户输入
# 接受用户输入,输入格式类似于[1,2,2,3],2
from typing import List

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 快慢指针
        fast = 0  # 快指针
        slow = 0  # 慢指针
        size = len(nums)
        while fast < size:  # 不加等于是因为,a = size 时,nums[a] 会越界
            # slow 用来收集不等于 val 的值,如果 fast 对应值不等于 val,则把它与 slow 替换
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow

def parse_input(input_str: str):
    # 去掉输入字符串中的方括号
    input_str = input_str.replace('[', '').replace(']', '')
    # 按逗号分割输入字符串
    parts = input_str.split(',')
    # 将前面部分解析为整数列表
    nums = list(map(int, parts[:-1]))
    # 将最后一个部分解析为目标值
    val = int(parts[-1])
    return nums, val

if __name__ == "__main__":
    input_str = input("请输入数组和目标值(格式为[1,2,2,3],2):")
    nums, val = parse_input(input_str)
    
    solution = Solution()
    new_length = solution.removeElement(nums, val)
    
    print(f"新的数组长度: {new_length}")
    print(f"修改后的数组: {nums[:new_length]}")


3.有序数组的平方 977

力扣977

C++

暴力解法

每个数平方之后,排个序,代码如下:

//时间复杂度是 O(n + nlogn)
class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        for (int i = 0; i < A.size(); i++) {
            A[i] *= A[i];
        }
        sort(A.begin(), A.end()); // 快速排序
        return A;
    }
};
双指针法

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

//时间复杂度O(n)
class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        int k = A.size() - 1;
        vector<int> result(A.size(), 0);
        for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
            if (A[i] * A[i] < A[j] * A[j])  {
                result[k--] = A[j] * A[j];
                j--;
            }
            else {
                result[k--] = A[i] * A[i];
                i++;
            }
        }
        return result;
    }
}
ACM模式用户输入
// 接受用户输入,输入格式类似于[-5,-2,-1,0,4,8]
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm> // 包含 std::remove 函数

using namespace std;

class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        int k = A.size() - 1;
        vector<int> result(A.size(), 0);
        for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
            if (A[i] * A[i] < A[j] * A[j])  {
                result[k--] = A[j] * A[j];
                j--;
            }
            else {
                result[k--] = A[i] * A[i];
                i++;
            }
        }
        return result;
    }
};

vector<int> parseInput(const string& input_str) {
    // 去掉输入字符串中的方括号
    string modified_input = input_str;
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), '['), modified_input.end());
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), ']'), modified_input.end());

    // 按逗号分割输入字符串
    stringstream ss(modified_input);
    string temp;
    vector<int> nums;
    
    while (getline(ss, temp, ',')) {
        nums.push_back(stoi(temp));
    }

    return nums;
}

int main() {
    string input_str;
    cout << "请输入数组(格式为[-5,-2,-1,0,4,8]):";
    getline(cin, input_str);
    
    vector<int> nums = parseInput(input_str);
    
    Solution solution;
    vector<int> result = solution.sortedSquares(nums);
    
    cout << "排序后的平方数组: ";
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

Python

暴力排序法
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        for i in range(len(nums)):
            nums[i] *= nums[i]
        nums.sort()
        return nums
暴力排序法+列表推导法
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        return sorted(x*x for x in nums)
双指针法
class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l, r, i = 0, len(nums)-1, len(nums)-1
        res = [float('inf')] * len(nums) # 需要提前定义列表,存放结果
        while l <= r:
            if nums[l] ** 2 < nums[r] ** 2: # 左右边界进行对比,找出最大值
                res[i] = nums[r] ** 2
                r -= 1 # 右指针往左移动
            else:
                res[i] = nums[l] ** 2
                l += 1 # 左指针往右移动
            i -= 1 # 存放结果的指针需要往前平移一位
        return res
ACM模式用户输入
# 接受用户输入,输入格式类似于[-5,-2,-1,0,4,8]
from typing import List

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        l, r, i = 0, len(nums)-1, len(nums)-1
        res = [float('inf')] * len(nums)  # 提前定义列表,存放结果
        while l <= r:
            if nums[l] ** 2 < nums[r] ** 2:  # 左右边界进行对比,找出最大值
                res[i] = nums[r] ** 2
                r -= 1  # 右指针往左移动
            else:
                res[i] = nums[l] ** 2
                l += 1  # 左指针往右移动
            i -= 1  # 存放结果的指针需要往前平移一位
        return res

def parse_input(input_str: str) -> List[int]:
    # 去掉输入字符串中的方括号
    input_str = input_str.replace('[', '').replace(']', '')
    # 按逗号分割输入字符串
    parts = input_str.split(',')
    # 将前面部分解析为整数列表
    nums = list(map(int, parts))
    return nums

if __name__ == "__main__":
    input_str = input("请输入数组(格式为[-5,-2,-1,0,4,8]):")
    nums = parse_input(input_str)
    
    solution = Solution()
    result = solution.sortedSquares(nums)
    
    print(f"排序后的平方数组: {result}")

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

力扣209

C++

暴力解法

两个for循环,然后不断的寻找符合条件的子序列,时间复杂度是O(n^2)。

//时间复杂度:O(n^2)
//空间复杂度:O(1)
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++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.size(); j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};
滑动窗口

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于等于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};
ACM模式用户输入
//接受用户输入,输入格式类似于[1,3,5,7,9,4,6],15
#include <iostream>
#include <vector>
#include <sstream>
#include <algorithm> // 包含 std::remove 函数

using namespace std;

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int result = INT32_MAX;
        int sum = 0; // 滑动窗口数值之和
        int i = 0; // 滑动窗口起始位置
        int subLength = 0; // 滑动窗口的长度
        for (int j = 0; j < nums.size(); j++) {
            sum += nums[j];
            // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件
            while (sum >= s) {
                subLength = (j - i + 1); // 取子序列的长度
                result = result < subLength ? result : subLength;
                sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == INT32_MAX ? 0 : result;
    }
};

vector<int> parseInput(const string& input_str, int& s) {
    // 去掉输入字符串中的方括号
    string modified_input = input_str;
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), '['), modified_input.end());
    modified_input.erase(remove(modified_input.begin(), modified_input.end(), ']'), modified_input.end());

    // 按逗号分割输入字符串
    stringstream ss(modified_input);
    string temp;
    vector<int> nums;
    
    while (getline(ss, temp, ',')) {
        nums.push_back(stoi(temp));
    }

    // 最后一个部分解析为目标值
    s = nums.back();
    nums.pop_back(); // 删除最后一个元素,因为它是目标值

    return nums;
}

int main() {
    string input_str;
    cout << "请输入数组和目标值(格式为[1,3,5,7,9,4,6],15):";
    getline(cin, input_str);
    
    int s;
    vector<int> nums = parseInput(input_str, s);
    
    Solution solution;
    int result = solution.minSubArrayLen(s, nums);
    
    cout << "最小子数组长度: " << result << endl;
    
    return 0;
}

Python

暴力解法
class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = len(nums)
        min_len = float('inf')
        
        for i in range(l):
            cur_sum = 0
            for j in range(i, l):
                cur_sum += nums[j]
                if cur_sum >= s:
                    min_len = min(min_len, j - i + 1)
                    break
        
        return min_len if min_len != float('inf') else 0
滑动窗口
class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = len(nums)
        left = 0
        right = 0
        min_len = float('inf')
        cur_sum = 0 #当前的累加值
        
        while right < l:
            cur_sum += nums[right]
            
            while cur_sum >= s: # 当前累加值大于目标值
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1
            
            right += 1
        
        return min_len if min_len != float('inf') else 0
ACM模式用户输入
# 接受用户输入,输入格式类似于[1,3,5,7,9,4,6],15
from typing import List

class Solution:
    def minSubArrayLen(self, s: int, nums: List[int]) -> int:
        l = len(nums)
        left = 0
        right = 0
        min_len = float('inf')
        cur_sum = 0  # 当前的累加值
        
        while right < l:
            cur_sum += nums[right]
            
            while cur_sum >= s:  # 当前累加值大于目标值
                min_len = min(min_len, right - left + 1)
                cur_sum -= nums[left]
                left += 1
            
            right += 1
        
        return min_len if min_len != float('inf') else 0

def parse_input(input_str: str) -> (List[int], int):
    # 去掉输入字符串中的方括号
    input_str = input_str.replace('[', '').replace(']', '')
    # 按逗号分割输入字符串
    parts = input_str.split(',')
    # 将前面部分解析为整数列表
    nums = list(map(int, parts[:-1]))
    # 将最后一个部分解析为目标值
    s = int(parts[-1])
    return nums, s

if __name__ == "__main__":
    input_str = input("请输入数组和目标值(格式为[1,3,5,7,9,4,6],15):")
    nums, s = parse_input(input_str)
    
    solution = Solution()
    result = solution.minSubArrayLen(s, nums)
    
    print(f"最小子数组长度: {result}")

5.螺旋矩阵 ② 59

力扣59

C++

//时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
//空间复杂度 O(1)
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop --) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j; j < n - offset; j++) {
                res[i][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};
ACM模式用户输入
#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
        int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
        int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
        int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
        int count = 1; // 用来给矩阵中每一个空格赋值
        int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
        int i,j;
        while (loop--) {
            i = startx;
            j = starty;

            // 下面开始的四个for就是模拟转了一圈
            // 模拟填充上行从左到右(左闭右开)
            for (j; j < n - offset; j++) {
                res[i][j] = count++;
            }
            // 模拟填充右列从上到下(左闭右开)
            for (i; i < n - offset; i++) {
                res[i][j] = count++;
            }
            // 模拟填充下行从右到左(左闭右开)
            for (; j > starty; j--) {
                res[i][j] = count++;
            }
            // 模拟填充左列从下到上(左闭右开)
            for (; i > startx; i--) {
                res[i][j] = count++;
            }

            // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
            startx++;
            starty++;

            // offset 控制每一圈里每一条边遍历的长度
            offset += 1;
        }

        // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
        if (n % 2) {
            res[mid][mid] = count;
        }
        return res;
    }
};

int main() {
    int n;
    cout << "请输入矩阵大小n: ";
    cin >> n;
    
    Solution solution;
    vector<vector<int>> result = solution.generateMatrix(n);
    
    cout << "生成的螺旋矩阵: " << endl;
    for (const auto& row : result) {
        for (int num : row) {
            cout << num << " ";
        }
        cout << endl;
    }
    
    return 0;
}

Python

//版本一:b站视频的解法
class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)]
        startx, starty = 0, 0               # 起始点
        loop, mid = n // 2, n // 2          # 迭代次数、n为奇数时,矩阵的中心点
        count = 1                           # 计数

        for offset in range(1, loop + 1) :      # 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset) :    # 从左至右,左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset) :    # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1) : # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1) : # 从下至上
                nums[i][starty] = count
                count += 1                
            startx += 1         # 更新起始点
            starty += 1

        if n % 2 != 0 :			# n为奇数时,填充中心点
            nums[mid][mid] = count 
        return nums
ACM模式用户输入
from typing import List

class Solution:
    def generateMatrix(self, n: int) -> List[List[int]]:
        nums = [[0] * n for _ in range(n)]
        startx, starty = 0, 0  # 起始点
        loop, mid = n // 2, n // 2  # 迭代次数、n为奇数时,矩阵的中心点
        count = 1  # 计数

        for offset in range(1, loop + 1):  # 每循环一层偏移量加1,偏移量从1开始
            for i in range(starty, n - offset):  # 从左至右,左闭右开
                nums[startx][i] = count
                count += 1
            for i in range(startx, n - offset):  # 从上至下
                nums[i][n - offset] = count
                count += 1
            for i in range(n - offset, starty, -1):  # 从右至左
                nums[n - offset][i] = count
                count += 1
            for i in range(n - offset, startx, -1):  # 从下至上
                nums[i][starty] = count
                count += 1
            startx += 1  # 更新起始点
            starty += 1

        if n % 2 != 0:  # n为奇数时,填充中心点
            nums[mid][mid] = count
        return nums

if __name__ == "__main__":
    n = int(input("请输入矩阵大小n: "))
    
    solution = Solution()
    result = solution.generateMatrix(n)
    
    print("生成的螺旋矩阵: ")
    for row in result:
        print(row)

//版本二:定义四个边界
class Solution(object):
    def generateMatrix(self, n):
        if n <= 0:
            return []
        
        # 初始化 n x n 矩阵
        matrix = [[0]*n for _ in range(n)]

        # 初始化边界和起始值
        top, bottom, left, right = 0, n-1, 0, n-1
        num = 1

        while top <= bottom and left <= right:
            # 从左到右填充上边界
            for i in range(left, right + 1):
                matrix[top][i] = num
                num += 1
            top += 1

            # 从上到下填充右边界
            for i in range(top, bottom + 1):
                matrix[i][right] = num
                num += 1
            right -= 1

            # 从右到左填充下边界

            for i in range(right, left - 1, -1):
                matrix[bottom][i] = num
                num += 1
            bottom -= 1

            # 从下到上填充左边界

            for i in range(bottom, top - 1, -1):
                matrix[i][left] = num
                num += 1
            left += 1

        return matrix
  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值