数组
一、二分查找
知识点:
- int middle = itBegin + (itEnd - itBegin)/ 2; // 防止溢出
在 C++ 中,如果两个整数相加的结果超过了整数类型的表示范围,就会发生溢出,导致结果不再是预期的值。
考虑到二分查找中常用到的 (itBegin + itEnd) / 2,如果 itBegin 和 itEnd 都是很大的正整数时,它们的和可能超过整数类型的最大表示范围,导致溢出。
而使用 (itBegin + (itEnd - itBegin) / 2) 这样的写法,可以避免这个问题。首先,通过 itEnd - itBegin 计算出两个迭代器之间的距离,然后再除以2。这样,即使 itBegin 和 itEnd 很大,它们之间的差值仍然是正数,不会导致溢出。
- middle - 1, middle + 1;
假如有一堆数字牌,从最左边到最右边,这些数字是按照从小到大的顺序排列的。我们要找的数字就叫做 "target"。
现在,我们先看最中间的一张牌的数字,这张牌的位置就是 middle。如果这张牌上的数字比我们要找的数字 "target" 大,那么我们就知道 "target" 只可能在这张牌的左边,因为数字是按照从小到大的顺序排列的。
所以,我们把牌堆缩小到左边一半,把最右边的牌移到 middle - 1 的位置。这样,我们就把寻找的范围缩小了一半,继续找。
这样做的好处有两点:
- 防止出现无限循环
如果有两张相邻的牌上的数字相等且都等于目标数字,我们每次猜中间的数字都不变,就陷入了无限循环,就像玩一个不停的游戏一样。
- 提高搜索效率
如果目标数字比中间的数字小,那就说明目标数字在这张牌的左边。
题目
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
题解
class Solution {
public:
int search(vector<int>& nums, int target) {
// 求vector长度 .size()
int itBegin = 0;
int itEnd = nums.size() - 1;
while (itBegin <= itEnd) {
int middle = itBegin + (itEnd - itBegin)/ 2; // 防止溢出
if (target < nums[middle])
{
itEnd = middle - 1;
}
else if (target > nums[middle])
{
itBegin = middle + 1;
}
else{
return middle;
}
}
return -1;
}
};
二、移除元素
知识点
这是一个快慢指针的问题,我想到了这个题解,但是没有想到快慢指针也可以用数字表示。
反正fast往前冲,slow只有符合条件的时候才赋值往前移动。
题目
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
- 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
- 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
题解
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
int fast = 0;
while(fast < nums.size())
{
if(nums[fast] != val)
{
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}
};
三、有序数组的平方
知识点
双指针 (使用条件,需要构造一个新数组)
题目
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
题解
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> result(nums.size(), 0); // vector的构造函数
int begin = 0;
int end = nums.size() - 1;
int Final = nums.size() - 1;
while(begin <= end){ // 这里的end和begin都是闭区间可以取等号
if(nums[end] * nums[end] > nums[begin] * nums[begin]){
result[Final] = nums[end] * nums[end];
end --;
Final --;
}
else{
result[Final] = nums[begin] * nums[begin];
begin ++;
Final --;
}
}
return result;
}
};
四、长度最小的子数组
知识点
滑动窗口
- 滑动窗口内容
- 滑动窗口的起始位置
- 滑动窗口的结束位置
题目
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
题解
public:
int minSubArrayLen(int target, vector<int>& nums) {
int subLength = 0;
int result = INT32_MAX;// 记录最大数
int sum = 0; // 用来记录子序列总和
int i = 0; // 用来记录起始指针位置
for (int j = 0; j < nums.size(); j++){// 滑动窗口的结束位置移动规则
sum += nums[j];
while(sum >= target)
{
subLength = j - i + 1; // 滑动窗口的内容
result = result > subLength ? subLength:result;
sum -= nums[i++]; // 滑动窗口的起始位置移动规则
}
}
return result == INT32_MAX ? 0 : result;
}
};
五、螺旋矩阵 II
知识点
不变性原则,规则是具有确定性的(比如开区间和闭区间,如果你决定了遍历都是【闭区间,开区间),那么请仔细确定接下来的步骤也应该遵守这个原则)
题目
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
题解
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> Matrix(n, vector<int>(n, 0));
int startX = 0;
int startY = 0;
int offset = 1;
int count = 1;
int k = 0;
int i, j;
while(k <= n/2){
j = startY;
i = startX;
for (j = startY; j < n - offset; j++){
Matrix[startX][j] = count++;
}
for (i = startX; i < n - offset; i++){
Matrix[i][j] = count++;
}
for (; j > startY; j--){
Matrix[i][j] = count++;
}
for (; i > startX; i--){
Matrix[i][j] = count++;
}
k++;
startX++;
startY++;
offset++;
}
if(n % 2 == 1){
Matrix[n/2][n/2] = count;
}
return Matrix;
}
};