链表——36、56、55、25

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、删除链表中重复的节点

  1. 首先添加一个头节点,以方便碰到第一个,第二个节点就相同的情况

  2. 设置 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);

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值