- 【加法模板】秒杀所有逐位相加
这道题和 2. 两数相加 一样,换汤不换药。
只要记住这个公式,不管两个数是列表形式,还是数组形式,都不会写错!
当前位 = (A 的当前位 + B 的当前位 + 进位carry) % 10 注意,AB两数都加完后,最后判断一下进位 carry, 进位不为 0 的话加在前面。
<加法模板>
while ( A 没完 || B 没完)
A 的当前位
B 的当前位
和 = A 的当前位 + B 的当前位 + 进位carry
当前位 = 和 % 10;
进位 = 和 / 10;
2. 两数相加(链表实现➕数组实现)
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头
**
53. 最大子数组和
** 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 示例 1: 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] 输出:6 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 **
思路:动态规划
**公式:定义f[i]表示以nums[i]结尾的最大子数组和。
分类讨论:
nums[i]单独组成一个子数组,那么f[i]=nums[i]。
nums[i]和前面的子数组拼起来,也就是在以nums[i−1]结尾的最大子数组和之后添加nums[i],那么f[i]=f[i−1]+nums[i]。
两种情况取最大值,得
o(n) 0(1)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
vector<int> f(nums.size());
f[0]= nums[0];
for(int i=1;i< nums.size();i++)
{
f[i]=max(f[i-1],0)+nums[i];
}
return ranges::max(f); //ranges::max(f) c++中求数组最大值的函数
}
};
238.除自身之外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 思路: ans[i]=p[i] * pre[i]; p[i]=p[i-1] * nums[i-1]; i从1到n pre[i]=pre[i+1] * nums[i+1]; i从n-2到0
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n=nums.size();
vector<int> pre(n,1);//新定义数组pre,初始值都为1
vector<int> p(n,1);
for(int i=n-2;i>=0;i--)
pre[i]=pre[i+1] * nums[i+1];
for(int i=1;i<n;i++)
p[i]=p[i-1] * nums[i-1];
vector<int> ans(n);//定义结果数组,初始值为0
for(int i=0;i<n;i++)
ans[i]=p[i] * pre[i];
return ans;
}
};
56.合并区间
思路:
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
sort(intervals.begin(), intervals.end());
vector<vector<int>> ans;
for (int i = 0; i < intervals.size();) {
int t = intervals[i][1];
int j = i + 1;
while (j < intervals.size() && intervals[j][0] <= t) {
t = max(t, intervals[j][1]);
j++;
}
ans.push_back({ intervals[i][0], t });
i = j;
}
return ans;
}
};
1.两数之和(使用哈希表解决)
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
思路:在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> a;
vector<int> b(2,-1);//用来承载结果,初始化一个大小为2,值为-1的容器b
for(int i=0;i<nums.size();i++)
{
auto it = a.find(target - nums[i]);//`auto`是C++11的类型推断,`it`是一个迭代器,指向找到的元素
if(it!=a.end())
{
return{it->second,i}; //哈希表迭代器it指向的键值对中的 值部分(即之前存储的索引),i为当前遍历的元素的索引。
//假设 it->second = 0,i = 1:return {0, 1}; 会构造一个包含两个元素 0 和 1 的 vector<int>,即 [0, 1]。
}
a[nums[i]]=i;
}
return {};
}
};
283移动零
思路:
class Solution {
public void moveZeroes(int[] nums) {
int i0=0;//把数组中0作为空位,将所有非零元素都移到数组左边的空位上,
//也就是交换非0和0的位置,保证交换后原来位置是新的空位(0)
for(int i=0;i<nums.length;i++)
{
if(nums[i]!=0)
{
int temp=nums[i];
nums[i]=nums[i0];
nums[i0]=temp;
i0++;
}
}
}
}
11.乘最多水的容器
思路:(Java版)
左右指针分别指向数组的看是和末尾位置,围成的面积为(坐标差*左右指针指向的数组最小值), 如果左指针指向的数组值比较小,说明左指针height[left] 与右边的任意线段都无法组成一个比 ans 更大的面积,左指针往后遍历;右指针同样情况就往前遍历;最终ans记录的是双指针遍历完后,最大的面积。
class Solution {
public int maxArea(int[] height) {
int ans=0;
int left=0;
int right=height.length-1;
while(left<right)
{
int area=(right-left) * Math.min(height[right],height[left]);
ans=Math.max(ans,area);
if(height[left]<height[right])
left++;
else
right--;
}
return ans;
}
}
15.三数之和
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans=new ArrayList();//新声明列表
Arrays.sort(nums); //先对数组进行升序遍历
int l=nums.length;
if(nums.length<3)
return ans;
for(int i=0;i<l;i++)
{
if(i>0 && nums[i]==nums[i-1])//如果前后两个数相同,结果会重复,先跳过
continue;
int L=i+1;//左指针
int R=l-1;//右指针
while(L<R)
{
if(nums[i]+nums[L]+nums[R]==0)
{
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));//ans.add()是在向ans列表中添加元素。Arrays.asList()的作用是将传入的参数转换为一个固定大小的列表
while(L<R && nums[L]==nums[L+1]) //如果左指针以及后面的指针数值相同,跳过该数,往后走
L++;
while(L<R && nums[R]==nums[R-1]) //如果右指针以及后面的指针数值相同,跳过该数,往前走
R--;
//向ans列表中添加第一组元素后,继续向后遍历,寻找下一组元素
L++;
R--;
}
else if(nums[i]+nums[L]+nums[R]<0)
L++;
else if(nums[i]+nums[L]+nums[R]>0)
R--;
}
}
return ans;
}
}
3.无重复字符的最长子串
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n = s.length(), ans = 0, left = 0;
unordered_map<char, int> cnt; // 维护从下标 left 到下标 right 的字符
for (int right = 0; right < n; right++) {
char c = s[right];
cnt[c]++;
while (cnt[c] > 1) { // 窗口内有重复字母
cnt[s[left]]--; // 移除窗口左端点字母
left++; // 缩小窗口
}
ans = max(ans, right - left + 1); // 更新窗口长度最大值
}
return ans;
}
};