链表常见算法题总结(Java)

本文深入探讨了链表数据结构的多种算法实现,包括链表反转、查找倒数第k个节点、从尾到头打印链表、合并排序链表等经典问题。通过具体代码示例,帮助读者理解并掌握链表操作的核心技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该帖主要对链表的常见算法题进行总结,也是方便查看,具体的题目要求和思路可以点开链接查看,欢迎大家指点。

1 反转链表

输入一个链表,反转链表后,输出新链表的表头。

    public ListNode ReverseList(ListNode head) {
      
        ListNode  reverse = null;
        ListNode  curr = head;
        ListNode  pre  = null;
        
        while(curr!=null){
            ListNode next = curr.next;
            if(next==null){
                reverse = curr;
            }
            
            curr.next=pre;
            pre = curr;
            curr = next;
        }
        
        return reverse;
    }

2 链表中第k个结点

输入一个链表,输出该链表中倒数第k个结点。

public ListNode FindKthToTail(ListNode head,int k) {
        ListNode p1 = head;//快指针
        ListNode p2 = head;//慢指针
        if(head==null || k<=0){ //链表为空或k结点不再链表中
           return null;
        }
        for(int i=0;i<k-1;i++){
            if(p1.next!=null){
                p1 = p1.next;
            }
            else{
                return null;
            }
        }

        while(p1.next!=null){
                p1 =p1.next;
                p2 = p2.next;
        }
        return p2;
    }

3 从尾到头打印链表

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        Stack<Integer> stack=new Stack<Integer>();
         ArrayList<Integer> arr =new ArrayList<Integer>();
        //把链表中的数推入栈
        while(listNode!=null){
            stack.push(listNode.val);
            listNode =listNode.next;
        }
        while(!stack.isEmpty()){
            arr.add(stack.pop());
        }
        return arr;
    }

4 合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1 == null){
            return list2;
        }
        else if(list2 == null){
            return list1;
        }
        else if(list1 ==null && list2 == null){
            return null;
        }
        ListNode res =null;
        if(list1.val<=list2.val){
              res=list1;
              res.next = Merge(list1.next,list2);
         }else if(list1.val>list2.val){
               res=list2;
               res.next = Merge(list1,list2.next); 
            }

        return res;
    }

5 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

public class Solution {
    TreeNode Head = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            return pRootOfTree;
        TreeNode curr = pRootOfTree;
        TreeNode pre = null;
        Stack<TreeNode> stack = new Stack<>();
        while(curr != null || !stack.isEmpty()){
            if(curr != null){
                stack.push(curr);
                curr = curr.left;
            }else{
                curr = stack.pop();
                if(Head == null){
                    Head = curr;
                    pre = Head;
                }//说明是第一个
                else{
                    pre.right = curr;
                    curr.left = pre;
                    pre = curr;
                }
                curr = curr.right;
            }
        }
        return Head;
        }}

6 删除链表中的重复结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

public ListNode deleteDuplication(ListNode pHead){
        if (pHead==null || pHead.next==null){
            return pHead;
        }
        ListNode gard = new ListNode(-1);
        gard.next = pHead;
        ListNode pre = gard;
        ListNode curr = pHead;
        while(curr!=null && curr.next!=null){
            if(curr.val == curr.next.val){
                int value = curr.val;
                while(curr.next!=null && curr.next.val == value){
                    curr = curr.next;
                }
                curr = curr.next;
                pre.next = curr;
            }
            else{
                pre = pre.next;
                curr = curr.next;
            }
        }
        return gard.next;
    }

7 链表中环的入口结点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

public ListNode EntryNodeOfLoop(ListNode pHead){
        ListNode p1 =pHead;
        ListNode p2 = pHead;
        while(p1!=null && p2!=null){
            p1 = p1.next;
            if(p2.next == null){
                return null;//p2.next ==null 时, 其next报错
            }
            p2 = p2.next.next;
            if(p1 == p2){//有环
                p2 = pHead;
                while(p1 != p2){
                    p1 = p1.next;
                    p2 = p2.next;
                }
                return p1;
            }
        }
        return null;
    }

 

### Java 链表算法题实现示例 #### 找到链表的中间节点 以下是基于快慢指针方法寻找链表中间节点的一个具体实现: ```java public class MiddleNodeFinder { public static ListNode findMiddle(ListNode head) { if (head == null || head.next == null) { return head; } ListNode slow = head; ListNode fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; } return slow; } public static void main(String[] args) { // 创建一个简单的链表: 1 -> 2 -> 3 -> 4 -> 5 ListNode node1 = new ListNode(1); ListNode node2 = new ListNode(2); ListNode node3 = new ListNode(3); ListNode node4 = new ListNode(4); ListNode node5 = new ListNode(5); node1.next = node2; node2.next = node3; node3.next = node4; node4.next = node5; ListNode middle = findMiddle(node1); System.out.println("中间节点的值:" + middle.val); // 输出应为3 } } ``` 上述代码通过定义两个指针 `slow` 和 `fast` 来分别以不同的速度遍历链表。当 `fast` 到达链表末端时,`slow` 正好位于链表的中间位置[^4]。 --- #### 反转单向链表 这是另一个常见链表操作——反转链表。下面是一个具体的实现方式: ```java public class ReverseLinkedList { public static ListNode reverseList(ListNode head) { ListNode prev = null; ListNode current = head; while (current != null) { ListNode nextTemp = current.next; current.next = prev; prev = current; current = nextTemp; } return prev; } public static void main(String[] args) { // 创建一个简单的链表: 1 -> 2 -> 3 -> 4 -> 5 ListNode node1 = new ListNode(1); ListNode node2 = new ListNode(2); ListNode node3 = new ListNode(3); ListNode node4 = new ListNode(4); ListNode node5 = new ListNode(5); node1.next = node2; node2.next = node3; node3.next = node4; node4.next = node5; ListNode reversedHead = reverseList(node1); // 打印反转后的链表 StringBuilder sb = new StringBuilder(); while (reversedHead != null) { sb.append(reversedHead.val).append(" "); reversedHead = reversedHead.next; } System.out.println(sb.toString().trim()); // 输出应为5 4 3 2 1 } } ``` 此代码片段展示了如何利用三个变量 (`prev`, `current`, `nextTemp`) 完成链表的原地反转过程[^3]。 --- #### 删除指定值的节点 删除链表中具有特定值的所有节点也是一个经典的练习。下面是其实现方案: ```java public class RemoveElementsFromList { public static ListNode removeElements(ListNode head, int val) { ListNode dummy = new ListNode(-1); dummy.next = head; ListNode current = dummy; while (current.next != null) { if (current.next.val == val) { current.next = current.next.next; } else { current = current.next; } } return dummy.next; } public static void main(String[] args) { // 创建一个简单的链表: 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 ListNode node1 = new ListNode(1); ListNode node2 = new ListNode(2); ListNode node3 = new ListNode(6); ListNode node4 = new ListNode(3); ListNode node5 = new ListNode(4); ListNode node6 = new ListNode(5); ListNode node7 = new ListNode(6); node1.next = node2; node2.next = node3; node3.next = node4; node4.next = node5; node5.next = node6; node6.next = node7; ListNode result = removeElements(node1, 6); // 打印处理后的链表 StringBuilder sb = new StringBuilder(); while (result != null) { sb.append(result.val).append(" "); result = result.next; } System.out.println(sb.toString().trim()); // 输出应为1 2 3 4 5 } } ``` 该函数创建了一个虚拟头结点来简化边界条件判断,并逐一遍历链表移除符合条件的节点。 --- #### 合并两个有序链表 最后介绍一种常见场景下的解决方案:合并两个已排序的链表形成一个新的升序排列列表。 ```java public class MergeTwoSortedLists { public static ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode dummy = new ListNode(-1); ListNode tail = dummy; while (l1 != null && l2 != null) { if (l1.val < l2.val) { tail.next = l1; l1 = l1.next; } else { tail.next = l2; l2 = l2.next; } tail = tail.next; } tail.next = (l1 != null) ? l1 : l2; return dummy.next; } public static void main(String[] args) { // 创建第一个链表: 1 -> 2 -> 4 ListNode list1_1 = new ListNode(1); ListNode list1_2 = new ListNode(2); ListNode list1_3 = new ListNode(4); list1_1.next = list1_2; list1_2.next = list1_3; // 创建第二个链表: 1 -> 3 -> 4 ListNode list2_1 = new ListNode(1); ListNode list2_2 = new ListNode(3); ListNode list2_3 = new ListNode(4); list2_1.next = list2_2; list2_2.next = list2_3; ListNode mergedList = mergeTwoLists(list1_1, list2_1); // 打印合并后的链表 StringBuilder sb = new StringBuilder(); while (mergedList != null) { sb.append(mergedList.val).append(" "); mergedList = mergedList.next; } System.out.println(sb.toString().trim()); // 输出应为1 1 2 3 4 4 } } ``` 这段程序采用迭代的方式逐步比较两个输入链表中的元素大小关系并将较小者加入新链表之中直至其中一个完全消耗完毕为止。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值