网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:输入:nums1 = [2], nums2 = []
输出:2.00000提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?
最直接的思路:合并后排序寻找数组的中位数
这种思路没有利用原先的两个数组就是已经正序的,这样的做法虽然思路简单,时空复杂度会很高,但是能快速AC一个困难级别的题目,也不是没有任何意义。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
// 合并数组之后再排序,时空复杂度最高
vector<int> v;
v.insert(v.end(),nums1.begin(),nums1.end());
v.insert(v.end(),nums2.begin(),nums2.end());
sort(v.begin(),v.end());
double n;
if(v.size()%2==0)
n = (double(v[v.size()/2])+double(v[(v.size()/2)-1]))/2;
else
n = v[v.size()/2];
return n;
}
};
双指针插入排序法
利用了两个数组都是正序的性质,使用双指针进行排序,时间复杂度有所提高
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
// 利用数组正序的性质,双指针插入排序
vector<int> v;
int i = 0, j = 0;
while (i < nums1.size() && j < nums2.size()) {
if (nums1[i] < nums2[j]) {
v.push\_back(nums1[i]);
i++;
} else if (nums1[i] > nums2[j]) {
v.push\_back(nums2[j]);
j++;
} else {
v.push\_back(nums1[i]);
v.push\_back(nums2[j]);
i++;
j++;
}
}
if (i < nums1.size()) {
while (i < nums1.size()) {
v.push\_back(nums1[i]);
i++;
}
} else if (j < nums2.size()){
while (j < nums2.size()) {
v.push\_back(nums2[j]);
j++;
}
}
double n;
if(v.size()%2==0)
n = (double(v[v.size()/2])+double(v[(v.size()/2)-1]))/2;
else
n = v[v.size()/2];
return n;
}
};
双指针优化版本
其实不用计算完全部的数组再做判断,只需要做出将数组计算到中间的位置然后进行判断即可,这样理论上会剩下一半的时间复杂度。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
// 利用数组正序的性质,双指针插入排序
// 其实不用全部将其排序完毕,我们只需要中间的数即可终止程序
length = nums1.size() + nums2.size();
double n;
vector<int> v;
int i = 0, j = 0;
while (i < nums1.size() && j < nums2.size()) {
if (nums1[i] < nums2[j]) {
v.push\_back(nums1[i]);
i++;
} else if (nums1[i] > nums2[j]) {
v.push\_back(nums2[j]);
j++;
} else {
v.push\_back(nums1[i]);
v.push\_back(nums2[j]);
i++;
j++;
}
// 只用计算到一半即可
if (v.size() >= length/2 + 1)
return help(v);
}
if (i < nums1.size()) {
while (i < nums1.size()) {
v.push\_back(nums1[i]);
i++;
if (v.size() >= length/2 + 1) {
return help(v);
}
}
} else if (j < nums2.size()){
while (j < nums2.size()) {
v.push\_back(nums2[j]);
j++;
if (v.size() >= length/2 + 1)
return help(v);
}
}
return 0;
}
private:
int length;
double help(vector<int> v) {
double ans;
if (length%2 == 0) {
ans = (double(v[length/2])+double(v[length/2 - 1]))/2;
} else {
ans = v[length/2];
}
return ans;
}
};
官方解法:二分查找
理论上时间复杂度一样,空间复杂度会有提升
class Solution {
public:
int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
/\* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较
\* 这里的 "/" 表示整除
\* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
\* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
\* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
\* 这样 pivot 本身最大也只能是第 k-1 小的元素
\* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
\* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
\* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
\*/
int m = nums1.size();
int n = nums2.size();
int index1 = 0, index2 = 0;
while (true) {
// 边界情况
if (index1 == m) {
return nums2[index2 + k - 1];
}
if (index2 == n) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
// 正常情况
int newIndex1 = min(index1 + k / 2 - 1, m - 1);
int newIndex2 = min(index2 + k / 2 - 1, n - 1);
int pivot1 = nums1[newIndex1];
int pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
}
else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int totalLength = nums1.size() + nums2.size();
if (totalLength % 2 == 1) {
return getKthElement(nums1, nums2, (totalLength + 1) / 2);
}
else {
return (getKthElement(nums1, nums2, totalLength / 2) + getKthElement(nums1, nums2, totalLength / 2 + 1)) / 2.0;
}
}
};
26. 删除有序数组中的重复项
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}示例 1:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。提示:
0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列
双指针法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ntJG4jXp-1631407998734)(C:\Users\10521\Desktop\GIF.gif)]
C
int removeDuplicates(int\* nums, int numsSize) {
if (numsSize == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < numsSize) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
C++
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
};
原地删除法:
和下面的LeetCode27题一样的方式,使用erase,不会有内存泄漏的风险,但是样例测出来的时间复杂度会比下面的方式高,对比一下时间,还是很明显的:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
// 原地删除法
if (nums.size() < 2)
return nums.size();
for (int i = 1; i < nums.size(); i++) {
if (nums[i - 1] == nums[i]) {
nums.erase(nums.begin() + i);
i--;
}
}
return nums.size();
}
};
手动删除法:会有内存泄漏的风险
我们这里只返回了 ++i 长度的数组,会造成什么呢,后面长度数组我们没有返回,也没有管,OJ也只会去读取我们返回长度的数组,所以这里虽然时间复杂度上优化了很多,但是我觉得这这种方法并不好
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size() < 2)
return nums.size();
// 手动删除的方式,不断交换并删除前面没有被删除长度的方式
// 虽然避免了每次erase造成时间复杂度上的压力,但是会有内存泄漏的风险
int i = 0;
for(int j = 1; j < nums.size(); j++) {
if(nums[i] != nums[j]){
i++;
nums[i] = nums[j];
}
}
return ++i;
}
};
27. 移除元素
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}示例 1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。提示:
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vetlnDhH-1631407998734)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905103459501.png)]
C语言版本
int removeElement(int\* nums, int numsSize, int val) {
int left = 0;
for (int right = 0; right < numsSize; right++) {
if (nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
C++版本
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size();
int left = 0;
for (int right = 0; right < n; right++) {
if (nums[right] != val) {
nums[left] = nums[right];
left++;
}
}
return left;
}
};
C语言版本
int removeElement(int\* nums, int numsSize, int val) {
int left = 0, right = numsSize;
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
C++版本
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left = 0, right = nums.size();
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return left;
}
};
33. 搜索旋转排序数组
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
示例 1:
输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4
示例 2:输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1
示例 3:输入:nums = [1], target = 0
输出:-1提示:
1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-10^4 <= target <= 10^4进阶:你可以设计一个时间复杂度为 O(log n) 的解决方案吗?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GgPvMDxl-1631407998736)([外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pcuOMGSj-1631408135358)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905105535173.png#pic_center)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-akeFIXG2-1631407998737)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905105553366.png)]
C++版本
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};
53. 最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:输入:nums = [1]
输出:1
示例 3:输入:nums = [0]
输出:0
示例 4:输入:nums = [-1]
输出:-1
示例 5:输入:nums = [-100000]
输出:-100000提示:
1 <= nums.length <= 3 * 104
-105 <= nums[i] <= 105进阶:如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
C语言
int maxSubArray(int\* nums, int numsSize) {
int pre = 0, maxAns = nums[0];
for (int i = 0; i < numsSize; i++) {
pre = fmax(pre + nums[i], nums[i]);
maxAns = fmax(maxAns, pre);
}
return maxAns;
}
C++语言
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x: nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b3vqRl2q-1631407998738)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905112816474.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HERwfsSX-1631407998738)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905112845212.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YkuC3NP5-1631407998739)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905112903644.png)]
C语言
struct Status {
int lSum, rSum, mSum, iSum;
};
struct Status pushUp(struct Status l, struct Status r) {
int iSum = l.iSum + r.iSum;
int lSum = fmax(l.lSum, l.iSum + r.lSum);
int rSum = fmax(r.rSum, r.iSum + l.rSum);
int mSum = fmax(fmax(l.mSum, r.mSum), l.rSum + r.lSum);
return (struct Status){lSum, rSum, mSum, iSum};
};
struct Status get(int\* a, int l, int r) {
if (l == r) {
return (struct Status){a[l], a[l], a[l], a[l]};
}
int m = (l + r) >> 1;
struct Status lSub = get(a, l, m);
struct Status rSub = get(a, m + 1, r);
return pushUp(lSub, rSub);
}
int maxSubArray(int\* nums, int numsSize) {
return get(nums, 0, numsSize - 1).mSum;
}
C++
class Solution {
public:
struct Status {
int lSum, rSum, mSum, iSum;
};
Status pushUp(Status l, Status r) {
int iSum = l.iSum + r.iSum;
int lSum = max(l.lSum, l.iSum + r.lSum);
int rSum = max(r.rSum, r.iSum + l.rSum);
int mSum = max(max(l.mSum, r.mSum), l.rSum + r.lSum);
return (Status) {lSum, rSum, mSum, iSum};
};
Status get(vector<int> &a, int l, int r) {
if (l == r) {
return (Status) {a[l], a[l], a[l], a[l]};
}
int m = (l + r) >> 1;
Status lSub = get(a, l, m);
Status rSub = get(a, m + 1, r);
return pushUp(lSub, rSub);
}
int maxSubArray(vector<int>& nums) {
return get(nums, 0, nums.size() - 1).mSum;
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bowJM4Nr-1631407998740)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905113016998.png)]
152. 乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
示例 2:输入: [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
C++
class Solution {
public:
int maxProduct(vector<int>& nums) {
vector <int> maxF(nums), minF(nums);
for (int i = 1; i < nums.size(); ++i) {
maxF[i] = max(maxF[i - 1] \* nums[i], max(nums[i], minF[i - 1] \* nums[i]));
minF[i] = min(minF[i - 1] \* nums[i], min(nums[i], maxF[i - 1] \* nums[i]));
}
return \*max\_element(maxF.begin(), maxF.end());
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-thHU9yiH-1631407998741)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905113311024.png)]
C++
class Solution {
public:
int maxProduct(vector<int>& nums) {
int maxF = nums[0], minF = nums[0], ans = nums[0];
for (int i = 1; i < nums.size(); ++i) {
int mx = maxF, mn = minF;
maxF = max(mx \* nums[i], max(nums[i], mn \* nums[i]));
minF = min(mn \* nums[i], min(nums[i], mx \* nums[i]));
ans = max(maxF, ans);
}
return ans;
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QLn7uAEb-1631407998741)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905113346264.png)]
238. 除自身以外数组的乘积
给你一个长度为 n 的整数数组 nums,其中 n > 1,返回输出数组 output ,其中 output[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积。
示例:
输入: [1,2,3,4]
输出: [24,12,8,6]提示:题目数据保证数组之中任意元素的全部前缀元素和后缀(甚至是整个数组)的乘积都在 32 位整数范围内。
说明: 请不要使用除法,且在 O(n) 时间复杂度内完成此题。
进阶:
你可以在常数空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组不被视为额外空间。)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oHEOGF49-1631407998742)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905115230964.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-svM95ICc-1631407998742)(C:\Users\10521\Desktop\GIF2.gif)]
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
// L 和 R 分别表示左右两侧的乘积列表
vector<int> L(length, 0), R(length, 0);
vector<int> answer(length);
// L[i] 为索引 i 左侧所有元素的乘积
// 对于索引为 '0' 的元素,因为左侧没有元素,所以 L[0] = 1
L[0] = 1;
for (int i = 1; i < length; i++) {
L[i] = nums[i - 1] \* L[i - 1];
}
// R[i] 为索引 i 右侧所有元素的乘积
// 对于索引为 'length-1' 的元素,因为右侧没有元素,所以 R[length-1] = 1
R[length - 1] = 1;
for (int i = length - 2; i >= 0; i--) {
R[i] = nums[i + 1] \* R[i + 1];
}
// 对于索引 i,除 nums[i] 之外其余各元素的乘积就是左侧所有元素的乘积乘以右侧所有元素的乘积
for (int i = 0; i < length; i++) {
answer[i] = L[i] \* R[i];
}
return answer;
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qR24ke4A-1631407998743)(C:\Users\10521\AppData\Roaming\Typora\typora-user-images\image-20210905115436395.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lsAsrPPn-1631407998743)(C:\Users\10521\AppData\Roaming\Typora\typora-user-images\image-20210905115511822.png)]
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
vector<int> answer(length);
// answer[i] 表示索引 i 左侧所有元素的乘积
// 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
answer[0] = 1;
for (int i = 1; i < length; i++) {
answer[i] = nums[i - 1] \* answer[i - 1];
}
// R 为右侧所有元素的乘积
// 刚开始右边没有元素,所以 R = 1
int R = 1;
for (int i = length - 1; i >= 0; i--) {
// 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
answer[i] = answer[i] \* R;
// R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
R \*= nums[i];
}
return answer;
}
};
7. 整数反转
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 1:
输入:x = 123
输出:321
示例 2:输入:x = -123
输出:-321
示例 3:输入:x = 120
输出:21
示例 4:输入:x = 0
输出:0提示:
-231 <= x <= 231 - 1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xhVJm98O-1631407998743)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905120808894.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JLs8SuDo-1631407998745)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905120849830.png)]
C语言
int reverse(int x) {
int rev = 0;
while (x != 0) {
if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {
return 0;
}
int digit = x % 10;
x /= 10;
rev = rev \* 10 + digit;
}
return rev;
}
C++
class Solution {
public:
int reverse(int x) {
int rev = 0;
while (x != 0) {
if (rev < INT_MIN / 10 || rev > INT_MAX / 10) {
return 0;
}
int digit = x % 10;
x /= 10;
rev = rev \* 10 + digit;
}
return rev;
}
};
739. 每日温度
请根据每日 气温 列表 temperatures ,请计算在每一天需要等几天才会有更高的温度。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:输入: temperatures = [30,60,90]
输出: [1,1,0]提示:
1 <= temperatures.length <= 105
30 <= temperatures[i] <= 100
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lFfz1Q35-1631407998746)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905122304997.png)]
C++
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
vector<int> ans(n), next(101, INT_MAX);
for (int i = n - 1; i >= 0; --i) {
int warmerIndex = INT_MAX;
for (int t = temperatures[i] + 1; t <= 100; ++t) {
warmerIndex = min(warmerIndex, next[t]);
}
if (warmerIndex != INT_MAX) {
ans[i] = warmerIndex - i;
}
next[temperatures[i]] = i;
}
return ans;
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2O174PUW-1631407998746)(https://raw.githubusercontent.com/xkyvvv/blogpic/main/pic1/image-20210905122344158.png)]
方法二:单调栈
可以维护一个存储下标的单调栈,从栈底到栈顶的下标对应的温度列表中的温度依次递减。如果一个下标在单调栈里,则表示尚未找到下一次温度更高的下标。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& temperatures) {
int n = temperatures.size();
vector<int> ans(n);
stack<int> s;
for (int i = 0; i < n; ++i) {
while (!s.empty() && temperatures[i] > temperatures[s.top()]) {
int previousIndex = s.top();
ans[previousIndex] = i - previousIndex;
s.pop();
}
s.push(i);
}
return ans;
}
};
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:输入:nums = [3,3], target = 6
输出:[0,1]提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
C
int\* twoSum(int\* nums, int numsSize, int target, int\* returnSize) {
for (int i = 0; i < numsSize; ++i) {
for (int j = i + 1; j < numsSize; ++j) {
if (nums[i] + nums[j] == target) {
int\* ret = malloc(sizeof(int) \* 2);
ret[0] = i, ret[1] = j;
\*returnSize = 2;
return ret;
}
}
}
\*returnSize = 0;
return NULL;
}
C++
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};
代码
struct hashTable {
int key;
int val;
UT_hash_handle hh;
};
struct hashTable\* hashtable;
struct hashTable\* find(int ikey) {
struct hashTable\* tmp;
HASH\_FIND\_INT(hashtable, &ikey, tmp);
return tmp;
}
void insert(int ikey, int ival) {
struct hashTable\* it = find(ikey);
if (it == NULL) {
struct hashTable\* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey, tmp->val = ival;
HASH\_ADD\_INT(hashtable, key, tmp);
} else {
it->val = ival;
}
}
int\* twoSum(int\* nums, int numsSize, int target, int\* returnSize) {
hashtable = NULL;
for (int i = 0; i < numsSize; i++) {
struct hashTable\* it = find(target - nums[i]);
if (it != NULL) {
int\* ret = malloc(sizeof(int) \* 2);
ret[0] = it->val, ret[1] = i;
\*returnSize = 2;
![img](https://img-blog.csdnimg.cn/img_convert/76e9142eb1cf217bc6fa1cc8dd39c092.png)
![img](https://img-blog.csdnimg.cn/img_convert/8075d892348417abc684649551f8a9af.png)
![img](https://img-blog.csdnimg.cn/img_convert/a881d87bb0ce0fdc86949f66e78f03ad.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**
;
代码
struct hashTable {
int key;
int val;
UT_hash_handle hh;
};
struct hashTable\* hashtable;
struct hashTable\* find(int ikey) {
struct hashTable\* tmp;
HASH\_FIND\_INT(hashtable, &ikey, tmp);
return tmp;
}
void insert(int ikey, int ival) {
struct hashTable\* it = find(ikey);
if (it == NULL) {
struct hashTable\* tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey, tmp->val = ival;
HASH\_ADD\_INT(hashtable, key, tmp);
} else {
it->val = ival;
}
}
int\* twoSum(int\* nums, int numsSize, int target, int\* returnSize) {
hashtable = NULL;
for (int i = 0; i < numsSize; i++) {
struct hashTable\* it = find(target - nums[i]);
if (it != NULL) {
int\* ret = malloc(sizeof(int) \* 2);
ret[0] = it->val, ret[1] = i;
\*returnSize = 2;
[外链图片转存中...(img-oAboVqwp-1715746574927)]
[外链图片转存中...(img-jxFm4Zvo-1715746574927)]
[外链图片转存中...(img-KNNk05zv-1715746574927)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618658159)**