JZ15 反转链表
问题:
输入一个链表,反转链表后,输出新链表的表头。
示例:
输入:{1,2,3}
返回值:{3,2,1}
思路:
示例为单链表,定义三个指针p、q、s,分别从链表前三位开始,将 q的 next指向 p,接着三个变量后移一位,直到 p走到最后,终止循环。
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head == null){//输入{}
return null;
}else if(head.next == null){//输入{1}
return head;
}
//正常情况
ListNode p = head;
ListNode q = p.next;
ListNode s = q.next;
p.next = null;
while(q != null){//p走到最后
q.next = p;
p = q;
q = s;
if(s != null){
s = s.next;
}
}
return p;//返回逆转后的链表头节点
}
}
JZ16 合并两个排序的链表
问题:
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
示例:
输入:{1,3,5},{2,4,6}
返回值:{1,2,3,4,5,6}
思路:
定义一个新链表,s指向它的头节点 。
比较给定两个链表的头节点,将 s.next指向较小的一个,该节点向后移,s 移到该位置。
依次向后,直到某一个链表为空,结束循环,s.next指向剩下的一个。
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
ListNode list = new ListNode(0);//新链表
ListNode s = list;
while(list1 != null && list2 != null){
if(list1.val < list2.val){//比较,选择链接哪一个
s.next = list1;
s = s.next;
list1 = list1.next;
}else{
s.next = list2;
s = s.next;
list2 = list2.next;
}
}
if(list1 != null){//链接剩下不为空的一个
s.next = list1;
}else{
s.next = list2;
}
return list.next;
}
}
JZ55 链表中环的入口结点
- 描述:
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。- 输入描述:
输入分为2段,第一段是入环前的链表部分,第二段是链表环的部分,后台将这2个会组装成一个有环或者无环单链表- 返回值描述:
返回链表的环的入口结点即可。而我们后台程序会打印这个节点
- 示例1
输入:{1,2},{3,4,5}
返回值:3
说明:返回环形链表入口节点,我们后台会打印该环形链表入口节点,即3- 示例2
输入:{1},{}
返回值:“null”
说明:没有环,返回null,后台打印"null"- 示例3
输入:{},{2}
返回值:2
说明:只有环形链表节点2,返回节点2,后台打印2
思路:
快慢引用,定义两个指针 fast、slow,从链表头部开始走。
fast一次走 2步,slow一次走 1步。记录相遇节点。
fast从相遇节点开始走,slow从头节点开始走,每次个走一步,这时候他们相遇节点为环的入口。
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead) {
ListNode fast = pHead;
ListNode slow = fast;//快慢引用
while(fast != null && fast.next != null){//找相遇点
fast = fast.next.next;//走两步
slow = slow.next;//走一步
if(fast == slow){//相遇,结束循环
break;
}
}
if(fast == null || fast.next == null){//特殊情况
return null;
}
slow = pHead;
while(fast != slow){//找环入口
fast = fast.next;
slow = slow.next;
}
return fast;
}
}
JZ36 两个链表的第一个公共结点
题目:
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。
数据范围: n < 1000
要求:空间复杂度 O(1) ,时间复杂度 O(n)
- 示例1:
输入:{1,2,3},{4,5},{6,7}
返回值:{6,7}
第一个参数{1,2,3}代表是第一个链表非公共部分,第二个参数{4,5}代表是第二个链表非公共部分,最后的{6,7}表示的是2个链表的公共部分
这3个参数最后在后台会组装成为2个两个无环的单链表,且是有公共节点的- 示例2:
输入:{1},{2,3},{}
返回值:{}
说明:2个链表没有公共节点 ,返回null,后台打印{}
思路1:
定义两个指针 i、j,分别从两个链表首端开始遍历,长链表的指针先走差值步,接着 i、j 一起走,相遇点为相交节点。
public class Solution {
public ListNode FindFirstCommonNode(ListNode p, ListNode q) {
ListNode i = p;
ListNode j = q;
int c1 = 0,c2 = 0;
//记录两个链表长度
for(;i != null;i = i.next){
c1++;
}
for(;j != null;j = j.next){
c2++;
}
i = p;
j = q;
//长的一个先走差值步
if(c1 > c2){
int c = c1 - c2;
while(c != 0){
i = i.next;
c--;
}
}else{
int c = c2 - c1;
while(c != 0){
j = j.next;
c--;
}
}
//返回公共节点
while(i != null){
if(i == j){
return i;
}
i = i.next;
j = j.next;
}
return null;
}
}
思路2:使用HashMap,先遍历p,并将每个节点插入Map集合中,再遍历q,判断每个节点是否在集合中,在则输出。
import java.util.HashMap;
public class Solution {
public ListNode FindFirstCommonNode(ListNode p, ListNode q) {
ListNode i = p;
ListNode j = q;
HashMap<ListNode,Integer> map = new HashMap<>();
while(i != null){//第一个链表节点放入map集合中
map.put(i,i.val);
i = i.next;
}
while(j != null){
if(map.containsKey(j)){//判断哪些节点在集合中返回
return j;
}
j = j.next;
}
return null;
}
}
如何删除元素,使得时间复杂度为O(1)
思路:
- 正常情况:将要删除节点(node)的下一个节点的 value值复制到该节点,再链接node.next.next节点。(给定要删除的节点时,时间复杂度为O(1),若给定要删除的值,时间复杂度为O(n),需要通过遍历找与该值相等的节点)
- 若删除尾巴,找尾巴前一个节点
public static void delete(SingleLink link,int k){//给定链表和需要删除的值
SingleLink.Node i = link.getHead();
if(link.getTail().getValue().equals(k)){//要删除的节点是尾巴节点
while (i.getNext().getNext() != null){//找被删节点前一个
i = i.getNext();
}
i.setNext(null);
}else {//删除非尾巴节点
while (!i.getValue().equals(k)){
i = i.getNext();
}
i.setValue(i.getNext().getValue());
i.setNext(i.getNext().getNext());
}
}