36、两个链表的第一个公共节点
我们使用两个指针 node1,node2 分别指向两个链表 headA,headB 的头结点,然后同时分别逐结点遍历,当 node1 到达链表 headA 的末尾时,重新定位到链表 headB 的头结点;当 node2 到达链表 headB 的末尾时,重新定位到链表 headA 的头结点。
这样,当它们相遇时,所指向的结点就是第一个公共结点。
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null) return null;
ListNode n1 = headA;
ListNode n2 = headB;
while(n1 != n2){
n1 = n1 == null ? headB : n1.next;
n2 = n2 == null ? headA : n2.next;
}
return n1;
}
}
56、删除链表中重复的节点
-
首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况
-
设置 pre ,last 指针, pre指针指向当前确定不重复的那个节点,而last指针相当于工作指针,一直往后面搜索。
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
//删除链表中重复的结点,重复的不保留
if(pHead==null || pHead.next==null)return pHead;// 只有0个或1个结点,则返回
ListNode head=new ListNode(0); //添加头结点
head.next=pHead;
ListNode last=head,cur=pHead;
while(cur!=null && cur.next!=null){//当前不为空,下一个不为空
if(cur.val!=cur.next.val){ //当前值!=下一个值,则把当前指针后移
last=cur;
cur=cur.next;
}else{
int val=cur.val;
while(cur!=null && cur.val==val)// 当前值=下一个值,找到最后的一个相同节点
cur=cur.next;
last.next=cur; //最开始重复的last 指向当前值
}
}
return head.next;//最后返回头指针(娅指针)的next
}
}
力扣题解,简单题
链表常用方式,固定下来的解题:
方便对头节点的操作,创建哑节点dummyhead
cur = dummyhed, cur指向当前节点
cur = cur->next,进行链表遍历
双指针
public ListNode deleteNode(ListNode head, int val) {
if(head == null) return head;
ListNode cur = head;
ListNode pre = null;
if(cur.val == val) return head.next;
while(cur.val != val) {
pre = cur;
cur = cur.next;
}
pre.next = pre.next.next;
return head;
}
单指针
class Solution {
public ListNode deleteNode(ListNode head, int val) {
if (head == null) return null;
if (head.val == val) return head.next;
ListNode cur = head;
while (cur.next != null && cur.next.val != val)
cur = cur.next;
if (cur.next != null)
cur.next = cur.next.next;
return head;
}
}
55、链表中环的入口节点
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null || pHead.next == null){
return null;
}
ListNode fast = pHead;
ListNode slow = pHead;
while(fast != null && fast.next != null){
fast = fast.next.next;//快指针
slow = slow.next;
if(fast == slow){
ListNode slow2 = pHead;//初次相遇,让快指针指向头节点
while(slow2 != slow){//在开始同时走,第二次相遇就是环的入口
slow2 = slow2.next;
slow = slow.next;
}
return slow2;
}
}
return null;
}
}
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
if(pHead == null){
return null;
}
// 1.判断链表中有环
ListNode l=pHead,r=pHead;
boolean flag = false;
while(r != null && r.next!=null){
l=l.next;
r=r.next.next;
if(l==r){//快慢指针如果可以相遇 就有环
flag=true;
break;
}
}
if(!flag){
return null;
}else{
// 2.得到环中节点的数目
int n=1;
r=r.next;//快指针变慢,走一圈,再次跟慢指针相遇
while(l!=r){
r=r.next;
n++;
}
// 3.找到环中的入口节点
l=r=pHead;
for(int i=0;i<n;i++){//第先让快指针跑环结点大小n次,相当于把环从链表中剪掉
r=r.next;
}
while(l!=r){
l=l.next;
r=r.next;
}
return l;
}
}
}
25、复杂链表的复制
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
标准的复制链表的方法
class Solution {
public Node copyRandomList(Node head) {
Node cur = head;
Node dum = new Node(0), pre = dum;
while(cur != null) {
Node node = new Node(cur.val); // 复制节点 cur
pre.next = node; // 新链表的 前驱节点 -> 当前节点
// pre.random = "???"; // 新链表的 「 前驱节点 -> 当前节点 」 无法确定
cur = cur.next; // 遍历下一节点
pre = node; // 保存当前新节点
}
return dum.next;
}
}
哈希表的用法:始终牢记:Map中不存在重复的key,因为放入相同的key,只会把原有的key-value对应的value给替换掉
但是哈希冲突之后,会以linkedlist链表排列往后延长,只是因为不同的key计算得到了相同的hashcode,本质上key还是不同的
map.put("Xiao Ming", s); // 将"Xiao Ming"和Student实例映射并关联
Student target = map.get("Xiao Ming"); // 通过key查找并返回映射的Student实例
boolean containsKey(K key)
//遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
class Solution {
public Node copyRandomList(Node head) {
if(head == null) return null;
Node cur = head;
Map<Node, Node> map = new HashMap<>();
// 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
while(cur != null) {
map.put(cur, new Node(cur.val));
cur = cur.next;
}
cur = head;
// 4. 构建新链表的 next 和 random 指向
while(cur != null) {
map.get(cur).next = map.get(cur.next);
map.get(cur).random = map.get(cur.random);
cur = cur.next;
}
// 5. 返回新链表的头节点
return map.get(head);
}
}
牛客的解析,也是用的hashmap
//下面那段代码思维太混乱了,大家不要参考,如果要用map解决此题,看这段代码就好
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
RandomListNode p = pHead;
//第一次遍历 新建立节点
while(p != null){
RandomListNode newNode = new RandomListNode(p.label);
map.put(p, newNode);
p = p.next;
}
//第二次遍历 赋值映射关系
p = pHead;
while(p != null){
RandomListNode node = map.get(p);
node.next = (p.next == null)?null: map.get(p.next);
node.random = (p.random == null)?null: map.get(p.random);
p = p.next;
}
//最后的返回值
return map.get(pHead);
}
}