文章目录
- 一、数组的改变、移动
- 453. 最小操作次数使数组元素相等
- 665. 非递减数列
- 283. 移动零
- 二、数组的旋转
- 189. 轮转数组
- 396. 旋转函数
- 三、统计数组中的元素
- 645. 错误的集合
- 697. 数组的度
- 448. 找到所有数组中消失的数字
- 442. 数组中重复的数据
- 41. 缺失的第一个正数
- 四、数组的遍历
- 485. 最大连续 1 的个数
- 495. 提莫攻击
- 414. 第三大的数
- 628. 三个数的最大乘积
题目链接
解题思路:
n - 1
个元素增加 1
,等价于每次操作使 1
个元素减小 1
,最终让数组中的所有元素相等;C++代码:
class Solution {
public:
int minMoves(vector<int>& nums) {
int minv = nums[0];
for (auto x: nums) minv = min(minv, x);
int res = 0;
for (auto x: nums) res += x - minv;
return res;
}
};
题目链接
C++代码:
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
if (nums.size() < 3) return true;
for (int i = 1, j = 0; i < nums.size(); i++, j++) {
if (nums[i] < nums[j]) {
if (i + 1 < nums.size() && nums[i + 1] <= nums[j]) nums[j] = nums[i];
//else if (i + 1 < nums.size() && nums[i + 1] > nums[j]) nums[i] = nums[j];
else nums[i] = nums[j];
break;
}
}
for (int i = 1, j = 0; i < nums.size(); i++, j++)
if (nums[i] < nums[j])
return false;
return true;
}
};
题目链接
解题思路:
利用双指针,将非0
元素全部移动到数组前端,然后将慢指针指向的元素到数组末尾全部赋为0
。
C++代码:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i]) nums[j++] = nums[i];
}
for (int i = j; i < nums.size(); i++) nums[i] = 0;
}
};
题目链接
解题思路:
通过观察轮转后的数组特点,一般可通过reverse()
函数实现轮转。
C++代码:
class Solution {
public:
void rotate(vector<int>& nums, int k) {
k %= nums.size();
reverse(nums.begin(), nums.end());
reverse(nums.begin(), nums.begin() + k);
reverse(nums.begin() + k, nums.end());
}
};
题目链接
解题思路:
由题意可知:
F(0) = 0 * a[0] + 1 * a[1] + 2 * a[2] + ... + (n - 2) * a[n - 2] + (n - 1) * a[n - 1]
F(1) = 1 * a[0] + 2 * a[1] + 3 * a[2] + ... + (n - 1) * a[n - 2] + 0 * a[n - 1]
F(2) = 2 * a[0] + 3 * a[1] + 4 * a[2] + ... + 0 * a[n - 2] + 1 * a[n - 1]
F(3) = 3 * a[0] + 4 * a[1] + 5 * a[2] + ... + 1 * a[n - 2] + 2 * a[n - 1]
...
由以上式子可得:
F(1) - F(0) = a[0] + a[1] + a[2] + ... + a[n - 2] + a[n - 1] - n * a[n - 1]
F(2) - F(1) = a[0] + a[1] + a[2] + ... + a[n - 2] + a[n - 1] - n * a[n - 2]
F(3) - F(2) = a[0] + a[1] + a[2] + ... + a[n - 2] + a[n - 1] - n * a[n - 3]
...
所以,
令sum = a[0] + a[1] + a[2] + ... + a[n - 2] + a[n - 1]
,有:
F(1) = F(0) + sum - n * a[n - 1]
,
F(2) = F(1) + sum - n * a[n - 2]
,
F(3) = F(2) + sum - n * a[n - 3]
,
...
最终可得到F(0), F(1), ... , F(n - 1)
中的最大值。
C++代码:
class Solution {
public:
int maxRotateFunction(vector<int>& A) {
typedef long long LL;
LL sum = 0, cur = 0; //cur用于保存当前的F(x);
for (auto c: A) sum += c;
int n = A.size();
for (int i = 0; i < n; i ++ ) cur += i * A[i];
LL res = cur;
for (int i = n - 1; i >= 0; i -- ) {
cur += sum - (LL)n * A[i];
res = max(res, cur);
}
return res;
}
};
题目链接
解题思路:
可通过哈希函数统计每个数字出现的次数,当遍历到某个元素出现的次数大于1
时,此时说明该元素出现了重复,将该元素加入结果数组中,统计完所有数字出现的次数后,对1 ~ n
的每一个数进行遍历,当遍历到某个元素出现的次数为0
时,表明该元素丢失,将该元素加入结果数组。
C++代码:
class Solution {
public:
vector<int> findErrorNums(vector<int>& nums) {
unordered_map<int, int> hash;
vector<int> res;
for (int i = 0; i < nums.size(); i++) {
hash[nums[i]]++;
if (hash[nums[i]] > 1)
res.push_back(nums[i]);
}
for (int i = 1; i <= nums.size(); i++) {
if (!hash.count(i))
res.push_back(i);
}
return res;
}
};
题目链接
解题思路:
这道题的题意是找到数组中出现次数最多的数的最短连续子数组的长度。主要通过两次循环遍历完成以上操作,
C++代码:
class Solution {
public:
int findShortestSubArray(vector<int>& nums) {
unordered_map<int, int> cnt, minp, maxp;
int d = 0;
for (int i = 0; i < nums.size(); i++) {
int x = nums[i];
d = max(d, ++cnt[x]);
if (!minp.count(x)) minp[x] = i;
maxp[x] = i;
}
int res = INT_MAX;
for (auto x: nums) {
if (cnt[x] == d)
res = min(res, maxp[x] - minp[x] + 1);
}
return res;
}
};
题目链接
解题思路:
题目给出了一个数组,元素的取值在[1, n]
,要求从数组中找出[1, n]
的元素取值中所有没有出现的数字。
这道题可使用负号标记当前元素是否出现过,这里会用到元素值和下标的映射关系,具体做法如下:
0
,表明当前元素所对应的下标没有出现过,即找到一个没有出现的数字。依次遍历每个元素,即可得到结果数组。C++代码:
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
for (auto x: nums) {
x = abs(x);
if (nums[x - 1] > 0) nums[x - 1] *= -1;
}
vector<int> res;
for (int i = 0; i < nums.size(); i++)
if (nums[i] > 0)
res.push_back(i + 1);
return res;
}
};
题目链接
C++代码 1:
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> res;
for (auto x: nums) {
x = abs(x);
if (nums[x - 1] > 0) nums[x - 1] *= -1;
else res.push_back(x);
}
return res;
}
};
C++代码 2:
class Solution {
public:
vector<int> findDuplicates(vector<int>& nums) {
vector<int> res;
vector<int> cnt(nums.size(), 0);
for (int i = 0; i < nums.size(); i++) {
cnt[nums[i] - 1]++;
if (cnt[nums[i] - 1] == 2)
res.push_back(nums[i]);
}
return res;
}
};
题目链接
给你一个未排序的整数数组 nums
,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n)
并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
示例 2:
输入:nums = [3,4,-1,1]
输出:2
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
提示:
nums.length
<= 5 * 105nums[i]
<= 231 - 1解题思路:
题目给出了一个未排序的数组,要求我们找出其中没有出现的最小的正整数。简单来说,由于数组中总共有n
个元素,若1~n
都存在数组中,那么没有出现的最小正整数则为n + 1
;反之,没有出现的最小正整数位于1~n
。
(桶排序) 时间复杂度O(n)
, 空间复杂度O(1)
1
出现在nums[0]
的位置上,2
出现在nums[1]
的位置上,…,n
出现在nums[n-1]
的位置上,其他的数字不管。例如[3,4,-1,1]
将被排序为[1,-1,3,4]
nums
,找到第一个不在对应位置上的1
到n
的数。例如,排序后的[1,-1,3,4]
中第一个 nums[i] != i + 1
的是数字2
(注意此时i=1
)。时间复杂度分析:swap
元素到相应位置过程中,每个元素最多被换O(1)
次,时间复杂度O(n)
;遍历数组时间复杂度为O(n)
;所以总的时间复杂度还是O(n)
。
C++代码:
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n = nums.size();
for (int i = 0; i < n; i++)
while (nums[i] <= n && nums[i] > 0 && nums[nums[i] - 1] != nums[i])
swap(nums[i], nums[nums[i] - 1]) ;
for (int i = 0; i < n; i++)
if (nums[i] != i + 1)
return i + 1;
return n + 1;
}
};
题目链接
给定一个二进制数组 nums
, 计算其中最大连续 1
的个数。
示例 1:
输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
示例 2:
输入:nums = [1,0,1,1,0,1]
输出:2
提示:
nums.length
<= 105nums[i]
不是 0
就是 1
.解题思路:
双指针记录连续1
的起始位置和终止位置,不断更新连续1
的最大长度。
C++代码:
class Solution {
public:
int findMaxConsecutiveOnes(vector<int>& nums) {
int res = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 0) continue;
int j = i + 1;
while (j < nums.size() && nums[i] == nums[j]) j++;
res = max(res, j - i);
i = j;
}
return res;
}
};
题目链接
解题思路:
观察相邻两次攻击的时间间隔
duration
秒;因此可遍历timeSeries
数组,将每两次攻击的时间差与中毒持续时间进行比较,将这两者中的较小时间加到结果中。
C++代码:
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration) {
int res = 0;
for (int i = 1; i < timeSeries.size(); i++)
res += min(timeSeries[i] - timeSeries[i - 1], duration);
if (timeSeries.size()) res += duration;
return res;
}
};
题目链接
解题思路:
对数组先排序在去重,最终得到一个从小到大排序,元素不重复的数组。
若元素个数小于3,表明第三大数不存在,则返回数组最后一个元素;否则,返回倒数第三个元素。
C++代码:
class Solution {
public:
int thirdMax(vector<int>& nums) {
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
if (nums.size() < 3) return nums.back();
return *(nums.end() - 3);
}
};
题目链接
解题思路:
首先对数组进行排序,有两种情况可能会出现三个数的最大乘积:
当数组中存在两个或两个以上的负数时,取前两个元素相乘,即是让最小的两个负数相乘,然后相乘的结果再与最大的元素相乘,所产生的结果可能为最大乘积。
C++代码:
class Solution {
public:
int maximumProduct(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
return max(nums[n - 1] * nums[n - 2] * nums[n - 3], nums[0] * nums[1] * nums[n - 1]);
}
};