版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012292754/article/details/83154118
1 单链表翻转
1.1 迭代版本
时间复杂度 O(n),空间复杂度 O(1)
ListNode ReverseList(ListNode head)
{
ListNode temp = null, nextNode = null;
while(head != null) {
nextNode = head;
head.setNext(temp);
temp = head;
head = nextNode;
}
return temp;
}
1.2
public static Node reverse(Node list){
Node headNode = null;
Node preNode = null;
Node currNode = list;
while( currNode != null) {
Node nextNode = currNode.next;
if(nextNode == null) {
headNode = currNode;
}
currNode.next = preNode;
preNode = currNode;
currNode = nextNode;
}
return headNode;
}
2 链表中环的检测
Floyd 环判定法,使用在链表中具有不同移动速度的指针,一旦它们进入环就会相遇,即表示存在环。
boolean DoesListContainsLoop(ListNode head){
//时间复杂度O(n),空间复杂度O(1)
if(head==null) return fasle;
ListNode slowPtr=fastPtr=head;
while(fastPtr.getNext()!=null && fastPtr.getNext().getNext()!=null) {
slowPtr=slowPtr.getNext();
fastPtr=fastPtr.getNext().getNext();
if(slowPtr==fastPtr)
return true;
}
return false;
}
public static boolean checkCircle(Node list){
if(list == null) return false;
Node fast = list.next;
Node slow = list;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if(slow == fast) return true;
}
return fasle;
}
2.1 判断给定的链表是否存在环,如果存在,找到环的起始点
思路分析:在找到环后,初始化 slowPtr 使其指向表头节点。然后slowPtr 和 fastPtr 从各自的位置开始移动,每次只移动一个节点,它们相遇的位置就是环的起始位置。(可以用这种方法删除环)
ListNode FindBerginofLoop(ListNode head){
// 时间复杂度 O(n),空间复杂度 O(1)
if(head==null)
return null;
ListNode slowPtr=fastPtr=head;
boolean loopExists=false;
while(fastPtr.getNext()!=null && fastPtr.getNext().getNext()!=null) {
slowPtr = slowPtr.getNext();
fastPtr = fastPtr.getNext().getNext();
if(slowPtr==fastPtr) {
loopExists = true;
break;
}
}
if(loopExists) {
slowPtr=head;
while(slowPtr!=fastPtr) {
slowPtr = slowPtr.getNext();
fastPtr = fastPtr.getNext();
}
return slowPtr; //返回环的开始节点
}
return null; //环不存在
}
2.2 在Floyd 环判定算法中,如果两个指针每次分别移动2个节点和3个节点,而不是移动1个节点和2个节点,算法任然有效吗?
有效,但是复杂度可能增加。
2.3 判定给定的链表中是否存在环,若存在,返回环的长度
在找到链表中存在环后,保持slowPtr的指针不变,fastPtr 指针继续移动。每次移动 fastPtr 指针时,计数器变量加 1 ,直到 再一次回到 slowPtr 指针所在的位置。
// 时间复杂度 O(n),空间复杂度 O(1)
int findLoopLength(ListNode head){
ListNode slowPtr = fastPtr = heaed;
boolean loopExists = fasle;
int count = 0;
if(head == null) return 0;
while(fastPtr.getNext() != null && fastPtr.getNext().getNext() != null) {
slowPtr = slowPtr.getNext();
fastPtr = fastPtr.getNext().getNext();
if(slowPtr == fastPtr) {
loopExists = true;
break;
}
}
if(loopExists) {
fastPtr = fastPtr.getNext();
count++;
while(slowPtr != fastPtr) {
fastPtr = fastPtr.getNext();
count++;
}
count++;
return count;
}
return 0;
}
3 两个有序链表的合并
3.1 方法1
// 第一个 while 循环,将l1 和 l2 进行比较,谁小就合并到 listNode,直到l1 或者 l2 为空
// 第二、三个 while 循环 将了l1 或者l2 剩下的节点合并到 listNode
ListNode mergeSortedList(ListNode l1,ListNode l2){
ListNode listNode = new ListNode(0);
ListNode head = listNode;
while(l1 != null && l2 != null) {
if(l1.data <= l2.data) {
listNode.next = l1;
l1 = l1.next;
}else{
listNode.next = l2;
l2 = l2.next;
}
listNode = listNode.next;
}
while(l1 != null) {
listNode.next = l1;
l1 = l1.next;
listNode = listNode.next;
}
while(l2 != null) {
listNode.next = l2;
l2 = l2.next;
listNode = listNode.next;
}
return head.next;
}
3.2 方法2 递归法
//分治思想,每次拿一个小的出来,每次的动作相同
ListNode MergeLists(ListNode a,ListNode b){
ListNode result = null;
if(a==null) return b;
if(b==null) return a;
if(a.getData() <= b.getData()) {
result = a;
result.setNext(MergeLists(a.getNext(),b));
}else{
result = b;
result.setNext(MergeLists(b.getNext(),a));
}
return result;
}
3.3
public static Node mergeSortedLists(Node la,Node lb){
if(la == null) return lb;
if(lb == null) return la;
Node p = la;
Node q = lb;
Node head;
if(p.data < q.data) {
head = p;
p = p.next;
}else{
head = q;
q = q.next;
}
Node r = head;
while(p != null && q!= null) {
if(p.data < q.data) {
r.next = p;
p = p.next;
}else{
r.next = q;
q = q.next;
}
r = r.next;
}
if(p != null) {
r.next = p;
}else{
r.next = q;
}
return head;
}
4 删除链表倒数第 n 个节点
public static Node deleteLastKth(Node list,int k){
Node fast = list;
int i = 1;
while( fast != null && i < k) {
fast = fast.next;
++i;
}
if(fast == null) return list;
Node slow = list;
Node pre = null;
while(fast.next != null) {
fast = fast.next;
pre = slow;
slow = slow.next;
}
if(pre == null) {
list = list.next;
}else{
pre.next = pre.next.next;
}
return list;
}
5 求链表的中间节点
5.1 蛮力法
在链表中对每个节点统计其后的节点的个数,然后判定其是否为中间节点。
时间复杂度 O(N^2),空间复杂度 O(1)
5.2 一次扫描搞定
时间复杂度 O(n),空间复杂度 O(1)
让第一个指针的移动速度是另一个的2倍,当第一个到达表尾的时候,另一个指针则指向中间节点。
ListNode findMiddle(ListNode head){
ListNode slowPtr = fastPtr = head;
//不断循环,直到达到表尾(next的后继指针为 null,表示达到最后一个节点)
int i = 0;
while(fastPtr.getNext() != null) {
if(i == 0) {
fastPtr = fastPtr.getNext();
i = 1;
}
if(i == 1) {
fastPtr = fastPtr.getNext();
slowPtr = slowPtr.getNext();
i = 0;
}
}
return slowPtr;
}
public static Node findMidNode(Node list){
if(list == null) return null;
Node first = list;
Node slow = list;
while(fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
}
return slow;
}