文章目录
- 1.1两数之和【代码随想录已刷】
- 2.2两数相加
- 2.1.题目
- 2.2.解答
- 3.3无重复字符的最长子串
- 3.1.题目
- 3.2.解答
1.1两数之和【代码随想录已刷】
参考:力扣题目链接;自己的博客题解
2.2两数相加
参考:力扣题目链接;参考题解
2.1.题目
2.2.解答
这道题目的思路也非常简单,因为是倒序存储的数字,所以直接从尾巴的地方把两个数字相加,然后依次往后(也就是往高位)计算相加的结果即可,就是正常的加法运算。
所以程序只需要遍历两个链表,只要他们其中有一个不是空,就可以继续加结果:
- 两个都不是空很好理解,就是两个数相加
- 其中一个不是空,那么就是一个数位数更多,此时相加就只剩这个数所在的位
但是这里面有几个要注意的点:
- 主要当前位置的加法结果是否有进位,也就是是否像高位进1,因此需要有一个变量存储进位结果;
- 题目要求是新生成一个加法和的链表,所以不能修改给的两个链表,而是要自己新建一个链表;
- 需要使用虚拟头结点来生成链表,这样新建节点的时候赋值给
cur->next
,这样更方便。否则如果赋值给cur->val
,那么cur->next
应该指向什么节点?这样就不方便操作了。
最后给出代码如下,非常简单:
struct ListNode
{
int val;
ListNode* next;
ListNode(int val_) : val(val_), next(nullptr) {}
};
// 注意已经说的了l1/l2都不是空
ListNode *addTwoNumbers(ListNode *l1, ListNode *l2)
{
// 使用虚拟头结点,方便处理
ListNode* dummy = new ListNode(-1);
ListNode* cur = dummy;
int add = 0; // 前一个节点相加是否有进位,如果有就是1,没有就是0
// 开始逐个节点相加
while(l1 || l2)
{
int val = 0;
if(l1)
{
val += l1->val;
l1 = l1->next;
}
if(l2)
{
val += l2->val;
l2 = l2->next;
}
val += add; // 加上上次进位的值
cur->next = new ListNode(val % 10); // 使用虚拟头节点,这里通过next来新建下一个节点
add = val / 10; // 本次进位结果
cur = cur->next; // 更新数组位置
}
// 最后一次相加的结果可能还有进位,但是被l1 || l2的判断条件忽略了,所以还要判断最后一次
if(add)
cur->next = new ListNode(1); // 最后一个节点
return dummy->next; // 返回头节点
}
3.3无重复字符的最长子串
参考:力扣题目链接;参考题解
3.1.题目
3.2.解答
首先这道题目看最后的解释,这里说的是子串,而不是子序列。以字符串abcde
为例,二者区别如下:
- 子串:字符串,必须是相连的,比如
abc
、bcd
; - 子序列:序列,可以跳着选择,比如
abd
、ace
。
这道题要求得是子串,所以可以使用滑动窗口算法,使用左右两个指针,然后用一个哈希表存储滑窗中已经有的元素。
- 当右指针遍历到当前位置的元素的时候,从滑窗中寻找是否存在这个元素。如果存在,则一直移动滑窗的左指针,直到没有这个元素为止。
- 此时滑窗中没有重复元素,使用左右指针计算滑窗长度,并更新最长的滑窗长度
右指针遍历到头之后,就找到了所有符合条件的(即没有重复字符)滑窗,也就找到了最终答案。
最后给出代码如下,很简单:
int lengthOfLongestSubstring(string s)
{
unordered_set<char> uset; // 存储滑窗中存在的字符
int result = 0; // 最长的长度
int left = 0; // [left, right]滑动窗口
for(int right = 0; right < s.size(); right++)
{
// 如果滑窗中有这个字符,则一直移动左边界
while(uset.find(s[right]) != uset.end())
uset.erase(s[left++]);
// 运行到这里,滑窗中没有重复的字符
result = max(result, right - left + 1); // 长度
uset.insert(s[right]); // 插入当前字符
}
return result;
}