相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
intersectVal- 相交的起始节点的值。如果不存在相交节点,这一值为0listA- 第一个链表listB- 第二个链表skipA- 在listA中(从头节点开始)跳到交叉节点的节点数skipB- 在listB中(从头节点开始)跳到交叉节点的节点数
评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
示例 1:
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
示例 2:
输入:intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Intersected at '2'
解释:相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
示例 3:

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:No intersection
解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。
由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
这两个链表不相交,因此返回 null 。
提示:
listA中节点数目为mlistB中节点数目为n1 <= m, n <= 3 * 1041 <= Node.val <= 1050 <= skipA <= m0 <= skipB <= n如果
listA和listB没有交点,intersectVal为0如果
listA和listB有交点,intersectVal == listA[skipA] == listB[skipB]
解题思路
这段代码用于查找两个单链表的交点(intersection node)。其核心逻辑是使用两个指针 a 和 b 分别遍历链表 headA 和 headB,通过让指针在到达链表末尾时切换到另一个链表的头部,从而消除两个链表的长度差。如果两个链表相交,指针最终会相遇;否则,指针会同时变为 null,返回 null。
代码逻辑步骤
初始检查:如果
headA或headB为null,直接返回null(因为无交点)。初始化指针:
a指向headA,b指向headB。循环遍历:
循环条件:
a != null || b != null(只要其中一个指针不为null,就继续循环)。在循环内:
首先检查
a和b是否指向同一个节点(即a == b)。如果是,返回该节点(交点)。然后移动指针
a:如果a不为null,则a指向a.next;否则,a指向headB(切换到链表B的头部)。类似地移动指针
b:如果b不为null,则b指向b.next;否则,b指向headA(切换到链表A的头部)。
循环结束:如果循环退出(即两个指针都变为
null),说明没有交点,返回null。
为什么这样工作?
如果两个链表相交,指针
a和b在遍历过程中会同时到达交点(因为切换链表后,路径长度相同)。如果不想交,指针最终会同时变为
null(即都遍历了两个链表的全部节点),循环退出。
示例模拟
假设链表A: 1->2->3->null,链表B: 4->5->null,无交点。
指针
a和b的遍历路径:a: 1 → 2 → 3 → null → 切换为 headB (4) → 5 → nullb: 4 → 5 → null → 切换为 headA (1) → 2 → 3 → null
当
a和b都变为null时,循环退出,返回null。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
ListNode a = headA;
ListNode b = headB;
while(a != null || b != null){
if(a==b){
return a;
}
if(a!=null){
a = a.next;
}else{
a = headB;
}
if(b!=null){
b = b.next;
}else{
b = headA;
}
}
return null;
}
}无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。
示例 1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
0 <= s.length <= 5 * 104s由英文字母、数字、符号和空格组成
解题思路(滑动窗口)
代码实现了使用滑动窗口(双指针)和哈希集合来寻找最长无重复字符子串的长度。
让我们逐步梳理逻辑:
初始化:使用
set来记录当前窗口中的字符,left和right指针表示窗口的左右边界,maxSize记录最大长度。扩张窗口(右指针移动):如果当前字符不在
set中,将其加入set,更新maxSize,然后right++。收缩窗口(左指针移动):如果当前字符在
set中(重复),则不断移动left指针,并移除left对应的字符,直到重复字符被移除(即窗口不再包含当前right字符)。
class Solution {
public int lengthOfLongestSubstring(String s) {
HashSet<Character> set = new HashSet();
int maxSize = 0;
int left = 0;
int right = 0;
char[] ss = s.toCharArray();
while(right < ss.length){
if(!set.contains(ss[right])){
set.add(ss[right]);
maxSize = Math.max(maxSize,right - left +1);
right++;
}else{
while(set.contains(ss[right])){
set.remove(ss[left]);
left++;
}
}
}
return maxSize;
}
}

