字数太多了分开发。
LeetCode链表
1、83. 删除排序链表中的重复元素
方法一:
整两个指针,不为null就一直判断里面的元素是否相等,
相等:p1指向p2的后面(相当于删除),p2向后移,直到不相等。
不等:让p1到p2的位置,p2向后移动一位,继续找。
public ListNode deleteDuplicates(ListNode head) {
ListNode p1 = head;
if(p1 == null) return head;
ListNode p2 = head.next;
while(p1!=null&&p2!=null){
while((p1!=null&&p2!=null) && p1.val == p2.val){
p1.next = p2.next;
p2 = p2.next;
}
while((p1!=null&&p2!=null) && p1.val != p2.val){
p1 = p2;
p2 = p2.next;
}
}
return head;
}
方法二:递归
用递归的思路做,和这个题203. 移除链表元素很像啊,几乎一模一样。
因为删除的重复元素本质上就是移除链表元素嘛,当这个节点的值与下一个节点值相同,那就返回下一个节点的结果;如果不同,那就让当前节点指向下一个节点的结果,然后返回当前节点。
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
if(head.val == head.next.val){
// 相同返回下一个
return deleteDuplicates(head.next);
}
else{
head.next = deleteDuplicates(head.next);
return head;
}
}
2、82. 删除排序链表中的重复元素 II
用递归搞,这次的区别就是,把有重复的都删了,上一个题是留一个。
只需要修改值相等的逻辑,定义一个新节点指向当前节点的下一个的下一个节点,然后一直找,直到找到值不相等的,然后返回这个新节点的结果就好。
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
if(head.val == head.next.val){
// 一直找到不重复的返回
ListNode node = head.next.next;
while(node != null && node.val == head.val){
node = node.next;
}
return deleteDuplicates(node);
}
else{
head.next = deleteDuplicates(head.next);
return head;
}
}
3、21. 合并两个有序链表
最基本的写法,很简单,判断大小交替插入就好啦
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode p1 = list1, p2 = list2;
ListNode ans = new ListNode(-1, list1);
ListNode p = ans;
while(p1 != null && p2 != null){
if(p1.val < p2.val){
p.next = p1;
p = p.next;
p1 = p1.next;
}
else{
p.next = p2;
p = p.next;
p2 = p2.next;
}
}
p.next = (p1==null ? p2 : p1);
return ans.next;
}
主要考虑递归怎么做,当我们归的时候,是不是应该组成一个有序的链表,所以我们返回的节点就应该是值最小的,所以先把这个小的节点指向合并的结果,然后返回。
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1 == null || list2 == null){
return list1==null ? list2 : list1;
}
if(list1.val < list2.val){
list1.next = mergeTwoLists(list1.next, list2);
return list1;
}
else{
list2.next = mergeTwoLists(list1, list2.next);
return list2;
}
}
4、面试题 02.07. 链表相交
方法一:
我想到了一种递归方法,首先倒着来判断,如果找到地址相同的(p1==p2)就说明可能是交点,继续向前找,直到找到地址不同的。
那怎么倒数的节点呢,之前做过一个修改倒数第几个节点的题,写个递归就行了,递归的时候还需要知道链表的长度,于是先求出链表的size。
这样,求出a和b,如果a==b,更新ans。
代码如下:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA, p2 = headB;
int size1 = 0, size2 = 0;
while(p1 != null){
p1 = p1.next;
size1++;
}
while(p2 != null){
p2 = p2.next;
size2++;
}
ListNode ans = null;
for(int i = 1; i <= Math.max(size1, size2); i++){
ListNode a = recursion(headA, i, size1);
ListNode b = recursion(headB, i, size2);
if(a==b){
ans = a;
}
else{
break;
}
}
return ans;
}
public ListNode recursion(ListNode p ,int n, int size){
if(p==null || n == size){
return p;
}
return recursion(p.next, n+1, size);
}
}
方法二:
我怎么没想到呢,求出差值不就行了嘛。。。
还用我费老鼻子劲用递归,这个题求出size之后作差,差的结果记作pos,然后让长的那个链表指针向后移动pos位,这不就实现了链表尾对齐了嘛,然后就循环找有没有p1==p2,最后随便返回一个,p1和p2都可以,因为要是找不到p1和p2都是null。
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
ListNode p1 = headA, p2 = headB;
int size1 = 0, size2 = 0;
while(p1 != null){
p1 = p1.next;
size1++;
}
while(p2 != null){
p2 = p2.next;
size2++;
}
if(size2 > size1){
p1 = headB;p2 = headA;
}
else{
p1 = headA;p2 = headB;
}
int pos = Math.abs(size2 - size1);
while(p1 != null && pos > 0){
p1 = p1.next;
pos--;
}
while((p1 != null && p2 != null) && p1 != p2){
p1 = p1.next;
p2 = p2.next;
}
return p1;
}
5、141. 环形链表
判环算法,用快慢指针实现。
怎么判环呢?慢指针p1每次走1步,快指针p2每次走2步,如果p1==p2,那就说明有环。
根据以上思路,代码如下,注意可能空指针的情况要提前判断处理:
public boolean hasCycle(ListNode head) {
ListNode p1 = head;
if(p1 == null) return false;
ListNode p2 = head;
while(p2 != null && p2.next != null){
p1 = p1.next;
p2 = p2.next.next;
if(p1 == p2){
return true;
}
}
return false;
}
6、142. 环形链表 II
判环算法还能找到环的入口。
如何找到呢?当找到环之后,如图所示的位置
让p1指向head
然后p1、p2开始走,每次都走一步,注意是都走一步,那么他们相遇的地方就是入口了。
证明的话可以看看这个,讲的很清楚基础数据结构-058-链表-e10-判环算法2_哔哩哔哩_bilibili
public ListNode detectCycle(ListNode head) {
ListNode p1 = head, p2 = head;
if(p1 == null) return null;
while(p2 != null && p2.next != null){
p1 = p1.next;
p2 = p2.next.next;
if(p1 == p2){
// 寻找入口
p1 = head;
while(true){
if(p1 == p2){
return p1;
}
p1 = p1.next;
p2 = p2.next;
}
}
}
return null;
}