编程题——链表

本文介绍了多种链表操作,包括从尾到头打印链表、查找倒数第k个节点、链表反转、合并排序链表、复制复杂链表、找链表公共节点、寻找环的入口、删除重复节点、删除指定节点、判断回文链表、链表相加、奇偶链表排序及合并K个有序链表等。提供了详细的操作示例和代码实现。

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

题目:
  1. 从尾到头打印链表
    输入一个链表,从尾到头打印链表每个节点的值。
  2. 链表中倒数第k个结点
    输入一个链表,输出该链表中倒数第k个结点。
  3. 反转链表
    输入一个链表,反转链表后,输出新链表的表头。
  4. 合并两个排序的链表
    输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
  5. 复杂链表的复制(复制带随机指针的链表)
    输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
  6. 两个链表的第一个公共结点(相交链表)
    输入两个链表,找出它们的第一个公共结点。
  7. 链表中环的入口结点
    一个链表中包含环,请找出该链表的环的入口结点。
  8. 删除链表中重复的结点
    在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
  9. 删除链表中的节点
    请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。(只给定被删除的节点)
    输入: head = [4,5,1,9], node = 5
    输出: [4,1,9]
    解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
  10. 回文链表
    请判断一个链表是否为回文链表。
    示例 1:
    输入: 1->2
    输出: false
    示例 2:
    输入: 1->2->2->1
    输出: true
  11. 链表A+B求和 (两数相加)
    给定两个非空链表来表示两个非负整数。位数按照逆序方式存储,它们的每个节点只存储单个数字。将两数相加返回一个新的链表。
    你可以假设除了数字 0 之外,这两个数字都不会以零开头。
    示例:
    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807
  12. 奇偶链表
    给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
    请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
    示例 1:
    输入: 1->2->3->4->5->NULL
    输出: 1->3->5->2->4->NULL
    示例 2:
    输入: 2->1->3->5->6->4->7->NULL
    输出: 2->3->6->7->1->5->4->NULL
    说明:
    应当保持奇数节点和偶数节点的相对顺序。
    链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
  13. 合并K个元素的有序链表
    合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
    示例:
    输入:
    [
    1->4->5,
    1->3->4,
    2->6
    ]
    输出: 1->1->2->3->4->4->5->6
  14. 链表排序
    在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
    示例 1:
    输入: 4->2->1->3
    输出: 1->2->3->4
    示例 2:
    输入: -1->5->3->4->0
    输出: -1->0->3->4->5
代码如下:

1、从尾到头打印链表

输入一个链表,从尾到头打印链表每个节点的值

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*/
//方法1:栈思想:先进后出
public class Solution {
        public ArrayList<Integer> printListFromTailToHead(ListNode listNode) 
        {
            Stack<Integer>stack=new Stack<Integer>();
            ListNode pNode=listNode;
           //入栈
            while(pNode!=null){
                stack.push(pNode.val);
                pNode=pNode.next;
            }
            //出栈
            ArrayList<Integer> al=new ArrayList<>();
            while(!stack.isEmpty()){
                al.add(stack.pop());
            }
                return al;
    }
}

//方法2:递归思想
public class Solution {
    ArrayList<Integer>al=new ArrayList<>();
     public ArrayList<Integer> printListFromTailToHead(ListNode listNode) 
     {
         if(listNode!=null){
             this.printListFromTailToHead(listNode.next);
             al.add(listNode.val);
         }
         return al;
     }
}


2、链表中倒数第k个结点

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

public class FindKthToTail {
    public ListNode FindKthToTail(ListNode head,int k){
        //定义两个指针,p1,p2,
        //倒数第k个,即正数走n-k,总共n-1步,则p1先走k-1步,
        // 然后p1,p2一起走,p1到结尾,此时p2刚好走n-k,到达倒数第k个节点

        if(head==null||k<=0)
            return null;

        ListNode p1=head;
        ListNode p2=head;
        for (int i = 0; i <k-1 ; i++) {
            if(p1.next!=null)
                p1=p1.next;
            else
                return null;//这句至关重要,判断链表长度是否大于k
        }
        while(p1.next!=null){
            p1=p1.next;
            p2=p2.next;
        }
        return p2;
    }

}

3、反转链表

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

public class Solution {
       public ListNode ReverseList(ListNode head) {
         if(head==null)
             return null;
        //当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点
        //需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2
        //即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了
        //所以需要用到pre和next两个节点
        //1->2->3->4->5
        //1<-2<-3 4->5
        
         ListNode pre=null;
         ListNode next=null;
         ListNode cur=head;

         //pre, head, next
         while(cur!=null)//不是while(cur.next!=null)
         {
             //先用next保存head的下一个节点的信息,保证单链表不会因为失去head节点的原next节点而就此断裂
            // cur=head;
             next=cur.next;

             //保存完next,就可以让head从指向next变成指向pre了,
             cur.next=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值