24. 两两交换链表中的节点
Leetcode链接: link
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode previous = dummyhead;
ListNode node1 = dummyhead.next;
while(node1 != null && node1.next != null){
ListNode node2 = node1.next;
ListNode temp = node2.next;
previous.next = node2;
node2.next = node1;
node1.next = temp;
previous = node1;
node1 = temp;
}
return dummyhead.next;
}
}
这一题目要使用的三个不同的指针,如 代码随想录说的一样,看了图之后才能理顺很多东西,不然只能在脑海里自己构思每个指针的连接方法。
19.删除链表的倒数第N个节点
Leetcode链接: link
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummyhead = new ListNode(0);
dummyhead.next = head;
ListNode front = dummyhead;
ListNode end = dummyhead;
for(int i = 0; i < n+1 ; i++){
if(end == null){
return dummyhead.next;
}else{
end = end.next;
}
}
while(end != null){
end = end.next;
front = front.next;
}
front.next = front.next.next;
return dummyhead.next;
}
}
这题和之前的array有一题很像,也是删除array倒数的第几个element。做法其实是一样的,用快慢指针就可以在O(n)的时间内找到要删除的node的位置。先让end指针先走n+1步,然后再让front指针和end指针一起走,知道end指针达到最后。以为我们删除node需要在目标node前面一个node位置来删除。如果是array那题的话就不需要,end可以先走n步。
面试题 02.07.链表相交
Leetcode链接: link
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode node1 = headA, node2 = headB;
int len1 = 0;
int len2 = 0;
while(node1 != null){
len1++;
node1 = node1.next;
}
while(node2 != null){
len2++;
node2 = node2.next;
}
node1 = headA;
node2 = headB;
if(len1 > len2){
for(int i = 0; i < len1-len2; i ++){
node1 = node1.next;
}
}else if(len1 < len2){
for(int i = 0; i < len2-len1; i ++){
node2 = node2.next;
}
}
while (node1 != null) {
if(node1 == node2){
return node1;
}
node1 = node1.next;
node2 = node2.next;
}
return null;
}
}
这题是比较有意思的一题,我一开始想的方法和代码随想录上面的方法差不多。就是先遍历一遍,然后再把长的那个linkedlist的前面部分读完,再和短的一起读。后来看到官网有一种更加简洁的方法:
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode node1 = headA;
ListNode node2 = headB;
while (node1 != node2) {
if (node1 == null) {
node1 = headB; // 如果 node1 到达了链表末端,则切换到链表B的头部
} else {
node1 = node1.next;
}
if (node2 == null) {
node2 = headA; // 如果 node2 到达了链表末端,则切换到链表A的头部
} else {
node2 = node2.next;
}
}
return node1; // 返回相交节点,或在没有相交时返回 null
}
}
这个方法理解起来也很简单,就是在一个循环里,node1先向headA走,走完再走一遍headB,等于是走headA+headB的linkedlist,node2就相反先走headB再走headA,等于是走headB+headA的linkedlist.如果A和B在一个地方合体了,那他们的尾部肯定是一样的。而且他们长度也是一样的。
142.环形链表II
Leetcode链接: link
//hash table
public class Solution {
public ListNode detectCycle(ListNode head) {
Set<ListNode> set = new HashSet<ListNode>();
ListNode temp = head;
while (temp != null) {
if(set.contains(temp)){
return temp;
}else{
set.add(temp);
}
temp = temp.next;
}
return null;
}
}
第一想法就是使用hash table。把所有的node一个个添加到hash table里面。然后每次添加的时候检测hash table里是否又这个node,如果有就说明遇到了cycle。如果到最后变成null了就说明没有cycle。另外还有一个快慢指针的方法。他们的时间复杂度都是一样的O(n),空间复杂度则是hash table O(n), 快慢指针O(1).
总结
其实感觉没什么好总结的,个人感觉linkedlist只要理解了,其实比array还简单很多,因为array的玩法比linkedlist多很多。