代码随想录刷题day4
24-两两交换链表中的节点
这题完全不会,直接按照卡哥思路进行模拟:
从这三步的先后顺序中可以看出:需要记住两个临时地址,图中的节点1和节点3,因为第一步完成之后,如果采用临时变量记住节点1的地址,那么会丢失节点1的地址,同理,在完成第二步之后,如果不使用临时变量记住节点3的地址,也会丢失节点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; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
ListNode curr = new ListNode(0,head);
if(head != null && head.next != null){
head = head.next;
}
while(curr.next != null && curr.next.next != null){
ListNode temp1 = curr.next;
ListNode temp2 = curr.next.next.next;
// 第一步
curr.next = curr.next.next;
// 第二步
curr.next.next = temp1;
// 第三步
temp1.next = temp2;
// 更新curr的值,以便进行循环
curr = curr.next.next;
}
return head;
}
}
curr.next != null && curr.next.next != null这个条件很明显,如果没有同时存在两个元素,那么就不需要交换。
19-删除链表的第倒数第N个节点
这题也是使用双指针的思想来解决:
先找到正数第N个节点, 使用right指向它,left指向第一个元素,然后不断移动,直到right.next为null这时left指向的元素就是应该被删除的元素,但是同时也要使用一个指针用来记住left的前一个元素的地址
/**
* 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; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode cur = new ListNode(0, head);
int count = 1;
ListNode p = cur.next;
ListNode back = null;
ListNode front = cur;
while(p != null){
if(count == n){
back = p;
break;
}else{
count++;
p = p.next;
}
}
// 如果找不到对应索引元素,则直接返回head
if(back == null)return head;
p = cur.next;
// front在左,p在中间,back在右边
while(back.next != null){
front = p;
p = p.next;
back = back.next;
}
front.next = p.next;
return cur.next;
}
}
链表相交
首先要理解链表相交的意思:不是节点里面的值相同,而是指针指向的地址相同。思路是简单的,不过很考验基本功。
因此可以先计算每个链表的长度,然后将较长的链表移动到某个位置,使得从这个位置起,链表长度和较短链表长度一样,然后挨个比较地址,一遇到相等的地址则直接返回,若直到链表末尾都没有找到相同的地址,直接返回null,证明不相交
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public static int getLen(ListNode head){
int count = 0;
while(head != null){
count++;
head=head.next;
}
return count;
}
public static ListNode moveLen(ListNode head, int n){
int count = 0;
ListNode p = head;
while(count < n){
p = p.next;
count++;
}
return p;
}
public static ListNode compare(ListNode a, ListNode b){
while(a != b){
a=a.next;
b=b.next;
if(a == null){
return null;
}
}
return a;
}
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = getLen(headA);
int lenB = getLen(headB);
if(lenA > lenB){
int l = lenA - lenB;
ListNode pA = moveLen(headA, l);
return compare(pA, headB);
}else if(lenA< lenB){
int l = lenB - lenA;
ListNode pB = moveLen(headB, l);
return compare(pB, headA);
}else{
return compare(headA,headB);
}
}
}
142-环形链表
这道题卡哥推了很久的原理,得出了一些结论。但是我第一感觉就是使用hashset来做,空间复杂度变高了,不过代码简单也好理解啊hh。
public class Solution {
public ListNode detectCycle(ListNode head) {
// 判断有没有环,本质上这里是看有没有相同的地址
// 因此hashset又排上用场了,只是需要不断遍历。时间较长
// 但是时间复杂度也只有O(n)
HashSet<ListNode> set = new HashSet<>();
ListNode p = head;
if(p==null)return null;
while(p != null){
if(!set.add(p))return p;;
p = p.next;
}
return null;
}
}
总结
链表这些题就是要多看多练,感觉别无捷径,只有苦练,最后一题偷懒了,但是自己时间并不充裕,主打就是一个项目优先,论文优先。