LeetCode刷题 day07
一.两数相加(链表)
1.题目要求
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
2.题目解析
在这之前,我们知道十进制的运算方式,逢10进1,所以这里设置进制数carry。(因为是相加,carry只会是0或1。)
- 两个链表对应节点值为n1和n2,sum=n1+n2+carry,carry初始化为0,因为是逆序,进制的方向也是逆序,所以是从左向右进1。因为大于10要进制,所以保留下来的数为sn=sum%10,进制数carry=sum/10
- 这里以2->4->3和5->6->4为例:
2+5=7,
4+6=10,逢10进制,所以sn=10%10=0,carry=10/10=1。
3+4+carry(目前为1)=8。 - 注意:如果最后还有进制1,在最后添加1这个数字结点。
- 最后返回头结点即可
3.具体代码
其中,我添加了注释,方便理解:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
public ListNode addTwoNumbers1(ListNode l1, ListNode l2) {
// 创建头结点和尾结点指针
ListNode head = null, tail = null;
int carry = 0; // 进位值初始化为0
while (l1 != null || l2 != null) { // 遍历两个链表节点
int n1 = l1 != null ? l1.val : 0; // 获取链表l1当前节点的值,如果为空则为0
int n2 = l2 != null ? l2.val : 0; // 获取链表l2当前节点的值,如果为空则为0
int sum = n1 + n2 + carry; // 计算当前节点值的和以及进位值
if (head == null) { // 如果当前节点是结果链表的头结点
// 创建新节点,并将其同时赋值给head和tail
head = tail = new ListNode(sum % 10);
} else {
tail.next = new ListNode(sum % 10); // 创建新节点
tail = tail.next; // 更新tail为新节点,保持链表尾部正确
}
carry = sum / 10; // 更新进位值
if (l1 != null) {
l1 = l1.next; // 遍历到下一个l1的节点
}
if (l2 != null) {
l2 = l2.next; // 遍历到下一个l2的节点
}
}
if (carry > 0) { // 如果最后一次相加有进位
tail.next = new ListNode(carry); // 创建新节点,将进位值连接到结果链表的尾部
}
return head; // 返回结果链表的头结点
}
二.无重复字符的最长子串
1.题目要求
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。
示例 :
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
2.解析
- 首先想到的是暴力算法,双循环,但是时间复杂度直接来到了O(n^2)
- 这里推荐两种方法:双指针和map映射表,其中异曲同工之妙都是滑动窗口。
- 什么是滑动窗口呢?
第一次添加字符到集合中,依次添加,并记录长度。当遇到重复数字时,将起点重新设置到排除重复数字的后面。
3.双指针代码
public int lengthOfLongestSubstring3(String s) {
int n = s.length();
int maxLength = 0;
int i = 0, j = 0;
Set<Character> set = new LinkedHashSet<>(); // 用于存储窗口中的字符集合
while (i < n && j < n) {
if (!set.contains(s.charAt(j))) { // 如果窗口中不存在 s[j] 字符
set.add(s.charAt(j++)); // 将 s[j] 加入集合并同时向右移动 j 指针
maxLength = Math.max(maxLength, j - i); // 更新最长长度
} else {
set.remove(s.charAt(i++)); // 将 s[i] 从集合中移除并同时向右移动 i 指针
}
}
return maxLength;
}
4.map代码
public static int lengthOfLongestSubstring1(String s) {
int cast=0; //初始化最长长度
int n=s.length();
//map映射表
Map<Character,Integer> map=new HashMap<>();
//长度记录的起点和终点
for(int end=0,start=0;end<n;end++){
//从头开始获取字符串的字符
char solo=s.charAt(end);
//如果集合中已经含有该字符的话,窗口要滑动
if(map.containsKey(solo)){
start=Math.max(map.get(solo),start);
}
//更新map和长度cast
cast=Math.max(cast,end-+1);
//其中end+1表示字符在字符串中的位置+1
map.put(s.charAt(end),end+1);
}
return cast;
}