算法分析 [指针,链表] 2019-02-22

ListNode h = new ListNode(-1);
h.next = head;
ListNode cur = h;

cur引用的改变是不会影响h的引用指向地址,只有当cur第一次.next变化的时候,会直接影响到h的引用执行地址
记住h, cur分别是一个引用对象,指向同一个存储地址
cur的变化,只是指向新的存储地址,而h的指向不变
指针删除的时候,一定要使用头指针

1. 双指针解法

单链表有几个特性

  1. 设置一个target,用fast先走,走到step后,fast和slow一起走,直到fast走完,slow走的就是链表长度的从后往前的step长
  2. 有长短链表,想找到2个链表的后部一样长度,长短链表一起走,短链表走往开始走长链表,长链表多出的走完走短链表,之后两个链表就处于一个位置了

1.1 给定一个单链表,判断链表中是否有环

141. 链表判断环,只判断是否存在 Linked List Cycle easy
法1. 时间复杂度 -> 无环O(n),有环O(n+k), 空间复杂度O(1)
只是简单判断是否存在相遇跑圈,一人快一人慢,总有一圈会碰上
使用双指针法slow和fast两个指针slow速度是1fast速度是2
如果有环,fast最终与slow相遇
如果没有环,fast最终指向重点

142. 链表判断环,获取循环开始下标 Linked List Cycle II medium
在前面的查找循环示例中,假设我们每次移动较快的指针 2 步,每次移动较慢的指针 1 步。

如果没有循环,快指针需要 N/2 次才能到达链表的末尾,其中 N 是链表的长度。
如果存在循环,则快指针需要M 次才能赶上慢指针,其中 M 是列表中循环的长度

和前一题区别是,可能n次入循环才找到相遇节点,并且这个相遇点不是循环起始点的,只是相遇的一点
我的理解:
先确定有环,并且找到相遇的节点,由于v(fast) = v(2 * slow),因此相遇时,distance(fast)=distance(2*slow)
那只要大家一起从0位置开始走,slow从头开始fast向后走一步,同时开始一步一步走,走的次数n就是循环开始的节点

解题思路:分两个步骤,首先通过快慢指针的方法判断链表是否有环;接下来如果有环,则寻找入环的第一个节点。具体的方法为,首先假定链表起点到入环的第一个节点A的长度为a【未知】,到快慢指针相遇的节点B的长度为(a + b)【这个长度是已知的】。现在我们想知道a的值,注意到快指针p2始终是慢指针p走过长度的2倍,所以慢指针p从B继续走(a + b)又能回到B点,如果只走a个长度就能回到节点A。但是a的值是不知道的,解决思路是曲线救国,注意到起点到A的长度是a,那么可以用一个从起点开始的新指针q和从节点B开始的慢指针p同步走,相遇的地方必然是入环的第一个节点A。 文字有点绕,画个图就一目了然了~

1.3 两个单链表,查找共同后缀相交链表

160. 相交链表 Intersection of Two Linked Lists easy
有长短链表,想找到2个链表的后部一样长度,长短链表一起走,短链表走往开始走长链表,长链表多出的走完走短链表,之后两个链表就处于一个位置了

1.4 删除链表中从尾数第n个值,返回链表

19. 删除链表的倒数第N个节点 Remove Nth Node From End of List medium
法1. 时间复杂度O(2L),先统计链表长度,再倒数计算
法2. 时间复杂度O(L),设置一个target,用fast先走,走到step后,fast和slow一起走,直到fast走完,slow走的就是链表长度的从后往前的step长

1.5 对链表进行排序,奇数排前面偶数排后面

328. 奇偶链表 Odd Even Linked List medium
时间复杂度O(n),空间复杂度O(1)
需要用到三个指针,一个是奇数指针odd,一个偶数指针even,一个指向尾偶数最尾部的下一个指针ep。
此指针可以获取到下一个奇数和偶数,这样odd和even指针都可以变动

1.6 判断回文数

234. 回文数单链表 Palindrome Linked List easy
法1. 时间复杂度O(n),空间复杂度O(1)
使用双指针,slow,fast先定位到中位数,同时使用一个curslow走过的节点反转,如果fast.next==null说明是奇数个值,cur不做入值操作,否则是偶数个值需要入值
然后将slow和cur遍历对比

680. 允许删除一个字符判断字符串是否是回文数 Valid Palindrome II easy
法1. 时间复杂度O(n),空间复杂度O(1)
因为只允许删除一个值,因此当出现一次不一致的时候,排除左边/右边的值下标,继续后续回文数判断

1.7 合并两个列表

21. 合并两个有序链表 Merge Two Sorted Lists easy
法1.时间复杂度O(n),空间复杂度O(1)
使用头指针h,如果l1为空,就把l2放到h2的下一节点,否则相反。否则,如果l1大,入节点,否则l2入节点。返回头结点的下一节点

88. 合并有序数组 Merge Sorted Array easy
法1. 时间复杂度O(n),空间复杂度O(1)
需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值

1.8 对两链表进行累加

2. 两数相加 Add Two Numbers medium
时间复杂度O(max(m,n)),空间复杂度O(max(m,n))
一起相加,要判断是否进一位,如果有一个链表比另一个大,值也要与进位相加考虑
445. 两数相加 Add Two Numbers II medium
解法和一 一样,区别是,先对链表倒排,然后对累加的数也进行倒排

2. 双向链表

2.1 多重双向链表,父子合并成一条串行

430. 扁平化多级双向链表 Flatten a Multilevel Doubly Linked List medium
遍历父链表,每个节点调用合并函数
判断节点node是否存在子链表,如果存在,记录链表头first,对子链表进行遍历,直到最后一个不存在子链表的节点,获得链表尾last,对node进行插入子链表操作,需要考虑node没有后继的情况
改善方法,变成可以复用的方法

你可能感兴趣的:(算法分析 [指针,链表] 2019-02-22)