牛客网剑指offer -链表(java实现)

一、JZ6 从尾到头打印链表(简单)

1、使用栈装

import java.util.ArrayList;
import java.util.Stack;
public class Solution {

    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> list = new ArrayList<Integer>();
        Stack<Integer> stack = new Stack<Integer>();
        while(listNode != null) {
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.empty()) {
            list.add(stack.pop());
        }
        return list;
    }
}

2、递归

import java.util.ArrayList;
public class Solution {
    //递归函数
    public void recursion(ListNode head, ArrayList<Integer> res){ 
        if(head != null){
            //先往链表深处遍历
            recursion(head.next, res); 
            //再填充到数组就是逆序
            res.add(head.val); 
        }
    }
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        //递归函数解决
        recursion(listNode, res);
        return res;
    }
}

二、JZ24 反转链表(简单)

1、先使用栈装

import java.util.Stack;
public class Solution {
    public ListNode ReverseList(ListNode head) {
        Stack<ListNode> stack = new Stack<ListNode>();
        while(head != null) {
            stack.push(head);
            head = head.next;
        }
        if (stack.empty()) return null;
        ListNode listNode = stack.pop();
        ListNode result = listNode;
        while(!stack.empty()) {
            listNode.next = stack.pop();
            listNode = listNode.next;
        }
        listNode.next = null;
        return result;
    }
}

2、类似双向链表

public ListNode ReverseList(ListNode head) {
//新链表
ListNode newHead = null;
    while (head != null) {
        //先保存访问的节点的下一个节点,保存起来
        //留着下一步访问的
        ListNode temp = head.next;
        //每次访问的原链表节点都会成为新链表的头结点,
        //其实就是把新链表挂到访问的原链表节点的
        //后面就行了
        head.next = newHead;
        //更新新链表
        newHead = head;
        //重新赋值,继续访问
        head = temp;
    }
    //返回新链表
    return newHead;
}

三、JZ25 合并两个排序的链表(简单)

1、创建两个链表,一个用来记录表头返回结果,一个用来完善链表

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode listNode = null;
        ListNode result = null;
        if(list1 != null && list2 == null) {
            result = list1;
        }
        if(list1 == null && list2 != null) {
            result = list2;
        }
        if(list1 != null && list2 != null) {
            listNode = list1.val < list2.val ? list1 : list2;
            result = listNode;
            if(list1.val < list2.val) {
                list1 = list1.next;
            } else {
                list2 = list2.next;
            }
            while(list1 != null) {
                if (list2 != null) {
                    if(list1.val < list2.val) {
                        listNode.next = list1;
                        list1 = list1.next;
                    } else {
                        listNode.next = list2;
                        list2 = list2.next;
                    }
                    listNode = listNode.next;
                } else {
                    listNode.next = list1;
                    list1 = list1.next;
                    listNode = listNode.next;
                }
            }
            while(list2 != null) {
                listNode.next = list2;
                list2 = list2.next;
                listNode = listNode.next;
            }
         }
         return result;
        
    }
}

2、使用递归

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        // list1 list2为空的情况
        if(list1 == null || list2 == null){
            return list1 != null ? list1 : list2;
        }
        // 两个链表元素依次对比
        if(list1.val <= list2.val){
            // 递归计算 list1.next, list2
            list1.next = Merge(list1.next, list2);
            return list1;
        }else{
            // 递归计算 list1, list2.next
            list2.next = Merge(list1, list2.next);
            return list2;
        } 
    }
}

四、JZ52 两个链表的第一个公共结点(简单)

1、将两条链表分别加上另外一条链表,然后进行遍历,然后选择其中一条返回

public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode listNode1 = pHead1, listNode2 = pHead2;
            while (listNode1 != listNode2) {
                listNode1 = listNode1 != null ? listNode1.next : pHead2;
                listNode2 = listNode2 != null ? listNode2.next : pHead1;
            } 
            return listNode1;
    }
}

五、JZ23 链表中环的入口结点(中等)

1、使用HashSet或者ArrayList装,遍历链表并添加到集合,判断是否已添加进集合过

import java.util.HashSet;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        HashSet<ListNode> hashSet = new HashSet<ListNode>();
        while(pHead != null) {
            if(hashSet.contains(pHead)) {
                return pHead;
            }
            hashSet.add(pHead);
            pHead = pHead.next;
        }
        return null;
    }
}

2、快慢指针

public ListNode EntryNodeOfLoop(ListNode pHead) {
        if(pHead == null) return null;
        // 定义快慢指针
        ListNode slow = pHead;
        ListNode fast = pHead;
        while(fast != null && fast.next != null){
            // 快指针是满指针的两倍速度
            fast = fast.next.next;
            slow = slow.next;
            // 记录快慢指针第一次相遇的结点
            if(slow == fast) break;
        }
        // 若是快指针指向null,则不存在环
        if(fast == null || fast.next == null) return null;
        // 重新指向链表头部
        fast = pHead;
        // 与第一次相遇的结点相同速度出发,相遇结点为入口结点
        while(fast != slow){
            fast = fast.next;
            slow = slow.next;
        }
        return fast;
    }

六、JZ22 链表中倒数最后k个结点(简单)

1、用一个数组装起来,然后判断K值与数组的大小关系,执行对应的操作

import java.util.*;
import java.util.ArrayList;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pHead ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode FindKthToTail (ListNode pHead, int k) {
        // write code here
        ArrayList<ListNode> list = new ArrayList<ListNode>();
        ListNode listNode = pHead;
        while(listNode != null) {
            list.add(listNode);
            listNode = listNode.next;
        }
        if(k > list.size()) {
            return null;
        } else if(k == list.size()){
            return  pHead;  
        } else {
            int i = list.size() - k;
            for(; i> 0; i--) {
                pHead = pHead.next;
            }
            return pHead;
        }
    }
}

2、快慢指针,快指针先走K步,然后一起next,快指针走完就是结束的标志

import java.util.*;
public class Solution {
    public ListNode FindKthToTail (ListNode pHead, int k) {
        int n = 0;
        ListNode fast = pHead; 
        ListNode slow = pHead;
        //快指针先行k步
        for(int i = 0; i < k; i++){  
            if(fast != null)
                fast = fast.next;
            //达不到k步说明链表过短,没有倒数k
            else 
                return slow = null;
        }
        //快慢指针同步,快指针先到底,慢指针指向倒数第k个
        while(fast != null){ 
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

七、JZ35 复杂链表的复制(较难)

1、使用一个map,key跟value都是链表类型,用来存储链表所有的值,后面也用于确定复制链表的值

import java.util.Map;
import java.util.HashMap;
public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if (pHead == null) return null;
        Map<RandomListNode,RandomListNode> map = new HashMap<RandomListNode,RandomListNode>();
        RandomListNode listNode = pHead;
        while(listNode != null) {
            map.put(listNode, new RandomListNode(listNode.label));
            listNode = listNode.next;
        }
        listNode = pHead;
        while (listNode != null) {
            map.get(listNode).next = map.get(listNode.next);
            map.get(listNode).random = map.get(listNode.random);
            listNode = listNode.next;
        }
        return map.get(pHead);
    }
}

八、JZ76 删除链表中重复的结点(中等)

1、在链表头部新增一个节点,便于删除表头元素,如果next节点与next.next节点不为null,且值相等,记录当前值,通过while判断一直next到下一个不相等的值,如果值不等则直接next下一个值

public class Solution {
    public ListNode deleteDuplication(ListNode pHead) {
        if(pHead == null) return null;
        ListNode listNode = new ListNode(0);
        listNode.next = pHead;
        ListNode result = listNode;
        while(listNode.next != null && listNode.next.next !=null) {
            if(listNode.next.val == listNode.next.next.val) {
                int temp = listNode.next.val;
                while(listNode.next != null && listNode.next.val == temp) {
                    listNode.next = listNode.next.next;
                }
            } else {
                listNode = listNode.next;
            }

        }
        return result.next;

    }
}

2、使用map记录各节点值出现次数,在链表头部新增一个节点,便于删除表头元素,再次遍历链表,只保留出现次数为1的

import java.util.*;
public class Solution {
    public ListNode deleteDuplication(ListNode pHead) {
        //空链表
        if(pHead == null) 
            return null;
        Map<Integer,Integer> mp = new HashMap<>();
        ListNode cur = pHead;
        //遍历链表统计每个节点值出现的次数
        while(cur != null){ 
            if(mp.containsKey(cur.val))
                mp.put(cur.val, (int)mp.get(cur.val) + 1);
            else
                mp.put(cur.val,1);
            cur = cur.next;
        }
        ListNode res = new ListNode(0);
        //在链表前加一个表头
        res.next = pHead; 
        cur = res;
        //再次遍历链表
        while(cur.next != null){
            //如果节点值计数不为1 
            if(mp.get(cur.next.val) != 1) 
                //删去该节点
                cur.next = cur.next.next; 
            else
                cur = cur.next; 
        }
        //去掉表头
        return res.next; 
    }
}

九、JZ18 删除链表的节点(简单)

1、在链表头部新增一个节点,便于删除表头元素,遍历链表,判断next值是否等于给定的值,相等的话,next = next.next来跳过值相等的节点

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param head ListNode类 
     * @param val int整型 
     * @return ListNode类
     */
    public ListNode deleteNode (ListNode head, int val) {
        // write code here
        if(head == null) return null;
        ListNode listNode = new ListNode(0);
        listNode.next = head;
        ListNode result = listNode;
        while(listNode.next != null) {
            if(listNode.next.val == val) {
                listNode.next = listNode.next.next;
            } else {
                listNode = listNode.next;
            }
        }
        return result.next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值