【25届秋招备战C++】题型练习-数组
基础知识
189-轮转数组
https://leetcode.cn/problems/rotate-array/description/
解题思路:
引入新数组,存储轮转后的数据元素
向右轮转k个位置,即在新数组的第i+k位(当i+k<原数组大小时)对应原数组的第i位,
而对于超出数组大小的排序应从新数组的第0——i+k-1位依次排列,也就是说新数组i+k-原数组大小位对应原数组的第i位,总结而言就是进行取余计算。
最终还需要将新数组的数据赋值给原数组,可采用assign()函数。
//核心代码语句
vector<int> nums0(nums.size());//注意此处需设定vector分配空间大小否则会报runtime error
for(int i=0;i<nums.size();i++){
nums0[(i+k)%nums.size()]=nums[i];
}
nums.assign(nums0.begin(),nums0.end());
66-加1
https://leetcode.cn/problems/plus-one/
解题思路:从最后一位开始,依次向前推进,若最后一位不是9则直接加1返回,若最后一位是9则覆盖其值为0,继续循环。
//核心代码
for(int i=digits.size()-1;i>=0;--i)
{
if(++digits[i]<10)
{
return digits;
}
else
digits[i] = 0;
}
digits.insert(digits.begin(),1);
return digits;
724-寻找数组的中心下标
https://leetcode.cn/problems/find-pivot-index/description/
解题思路:中心下标左右两边和相等,那么总和+中心下标对应值=2倍的中心下标左和。
accumulate()函数实现数组求和 accumulate带有三个形参:头两个形参指定要累加的元素范围,第三个形参则是累加的初值。
#include<numeric>//vector求和函数accumulate()头文件
int pivotIndex(vector<int>& nums) {
int sum_left=0;
int sum_total=accumulate(nums.begin(),nums.end(),0);
for(int i=0;i<nums.size();i++)
{
if(2*sum_left+nums[i]==sum_total)
{
return i;
}
sum_left+=nums[i];
}
return -1;
}
485.最大连续1的数
https://leetcode.cn/problems/max-consecutive-ones/
解题思路:只有当数组中元素为1时才计数,所以可设置一个变量记录循环到当前位时连续1的个数,只要有0则该变量清空,可用乘法实现,即连续一的个数=(截至上一位连续一的个数 + 1)× 当前位的值。(这个解题思路太妙了,可惜不是我想出来的,膜拜大佬,另外此题算是比较典型的滑动窗口题之后算法总结可以再拿出来做一下)
class Solution {
public:
int findMaxConsecutiveOnes(vector<int>& nums) {
int max = 0, sum = 0;
for (int i = 0; i < nums.size(); i++) {
sum = (sum + 1) * nums[i];
max = max >= sum ? max : sum;
}
return max;
}
};
238-除自身以外数组的乘积
https://leetcode.cn/problems/product-of-array-except-self/
解题思路:不能用除法,只能用乘法,则数组元素可被分为自身左边与右边两组分别进行乘法计算,最后再将其结果相乘即可
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
if(nums.size()==0)
return {};
vector<int> result(nums.size(),1);
int right=1;
result[0]=1;
for(int i=1;i<nums.size();i++)
{
result[i]=result[i-1]*nums[i-1];
}
for(int j=nums.size()-2;j>=0;j--)
{
right=right*nums[j+1];
result[j]=result[j]*right;
}
return result;
}
};
498-对角线遍历
https://leetcode.cn/problems/diagonal-traverse/description/
解题思路:按对角线遍历的话首先可将移动方向分为向上或向下(严格来说是斜向上或斜向下),而同一对角线上各点的横纵坐标之和相同,相邻对角线的横纵坐标之和相差1,且横纵坐标之和为奇数时对角线方向向下,横纵坐标之和为偶数时对角线方向向上。方向变换的转折点是横坐标为0,纵坐标为n或纵坐标为0,横坐标为m时。
在向上的对角线中,当横纵坐标之和小于n时对应对角线的起始点则在x=0的第一行,纵坐标是和-横坐标,横纵坐标之和大于或等于n时对角线的起始点在x=和-列数+1的最后一行,纵坐标是列数-1
class Solution {
public:
vector<int> findDiagonalOrder(vector<vector<int>>& mat) {
vector<int> result;
int m=mat.size();
int n=mat[0].size();
for(int i=0;i<m+n-1;i++)
{
if(i%2)
{
int x= i<n ? 0:i-n+1;
int y= i<n ? i:n-1;
while(x<m && y>=0)
{
result.emplace_back(mat[x][y]);
x++;
y--;
}
}
else{
int x= i<m ? i:m-1;
int y= i<m ? 0:i-m+1;
while(y<n && x>=0)
{
result.emplace_back(mat[x][y]);
x--;
y++;
}
}
}
return result;
}
};
48-旋转图像
https://leetcode.cn/problems/rotate-image/solutions/526980/xuan-zhuan-tu-xiang-by-leetcode-solution-vu3m/
解题思路:先水平翻转,再对角线翻转(注意循环次数,水平翻转只要翻转一半即可否则会还原到初始状态,看了题解才恍然大悟)
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n / 2; ++i) {
for (int j = 0; j < n; ++j) {
swap(matrix[i][j], matrix[n - i - 1][j]);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < i; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};
73-矩阵置零
https://leetcode.cn/problems/set-matrix-zeroes/
解题思路:原地修改不能引入新数组,则需要先记录需要更改的位置
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int m=matrix.size();
int n=matrix[0].size();
vector<int> l(m);
vector<int> h(n);
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(matrix[i][j]==0)
{
l[i]=h[j]=1;
}
}
}
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(l[i]==1 ||h[j]==1)
{
matrix[i][j]=0;
}
}
}
}
};