注:本篇文章代码以及部分内容来源于代码随想录
C++基础知识补课
#include <iostream>
这一行代码包含了C++标准库中的输入输出流头文件iostream
。它提供了输入输出操作的功能,比如cin
用于输入,cout
用于输出。
#include <vector>
这一行代码包含了C++标准库中的容器类vector
。vector
是一种动态数组,可以自动调整大小,提供了方便的操作接口。
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
及其在数组中的索引index
。endl
用于换行。
关于引用:
引用类型(Reference)
在C++中,引用是一种类型,它是一个已经存在的变量的别名。通过引用,我们可以直接操作原变量,而无需复制数据。
引用的定义和使用
定义引用时使用&
符号。例如:
int a = 10;
int& ref = a; // ref是a的引用
在这个例子中,ref
是a
的引用,ref
和a
指向同一个内存地址。因此,通过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):函数参数
vector<int>& vec
是一个引用。这意味着函数modifyVector
直接操作传入的原始向量numbers
,所有的修改都会反映到numbers
中。 - 按值传递(代码片段2):函数参数
vector<int> vec
是按值传递。这意味着调用modifyVector
时,会创建numbers
的一个副本vec
,函数内的修改只影响副本,不会影响原始向量numbers
。
- 按引用传递(代码片段1):函数参数
-
函数执行结果:
- 按引用传递(代码片段1):函数
modifyVector
将numbers
的每个元素乘以2,修改后numbers
的内容是{2, 4, 6, 8, 10}
。输出结果是:2 4 6 8 10
。 - 按值传递(代码片段2):函数
modifyVector
只修改副本vec
,numbers
不变。输出结果仍然是原始内容:1 2 3 4 5
。
- 按引用传递(代码片段1):函数
代码片段1的详细执行过程(按引用传递):
main
函数定义并初始化numbers
为{1, 2, 3, 4, 5}
。- 调用
modifyVector(numbers)
,将numbers
的引用传递给vec
。 - 在
modifyVector
函数中,对vec
的每个元素乘以2,实际修改的是numbers
。 - 函数返回后,
numbers
的内容变为{2, 4, 6, 8, 10}
。 main
函数输出修改后的numbers
:2 4 6 8 10
。
代码片段2的详细执行过程(按值传递):
main
函数定义并初始化numbers
为{1, 2, 3, 4, 5}
。- 调用
modifyVector(numbers)
,将numbers
的副本传递给vec
。 - 在
modifyVector
函数中,对vec
的每个元素乘以2,但这只影响副本vec
,不影响原始向量numbers
。 - 函数返回后,
numbers
的内容仍然是{1, 2, 3, 4, 5}
。 main
函数输出原始的numbers
:1 2 3 4 5
。
总结
- 按引用传递:函数直接操作原始数据,提高效率并使修改直接反映到原数据上。
- 按值传递:函数操作的是数据的副本,原数据保持不变,适用于不希望函数修改原数据的情况。
选择按引用还是按值传递取决于你的需求:是否希望函数修改原数据,以及是否需要提高性能(避免不必要的数据复制)。
数组
1.二分查找法 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
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
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
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
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