链表常见问题

反转链表

将一个链表进行反转,1->2->3->4变为4->3->2->1。
这应该是对链表最经典的操作了,在以前学过的数据结构里,使用的方法是头插法。理解上只需要两个指针,pre指针保存新链表的头,p指针保存断开以后的部分。第一步如下:

第一步
之后head指针向后移动,也就是和p指针指向同一个。进入第二步,p指针向后移动,让head指针的next指向pre,反转一个。pre向后移动,head向后移动。代码如下:

public class 反转链表 {
    public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.add(2);
        head.add(3);
        head.add(4);
        head.add(5);
        System.out.println(head);
        System.out.println(convert(head));
    }
    static ListNode convert(ListNode head){
        ListNode pre = null;   //头
        ListNode p = null;   //保存指针
        while (head != null){
            p = head.next;
            head.next = pre;
            pre = head;   //头插
            head = p;
        }
        return pre;
    }
}

[0.110s][warning][os,thread] Attempt to allocate stack guard pages failed.
[1->2->3->4->5]
[5->4->3->2->1]

回文链表

判断一个链表是否是回文,就像回文数一样:12321、123321都是,链表形式也是这样。
首先的思路是借用栈结构,先进后出,12321入栈后,如果出栈还是12321那么就满足。1234入栈以后出栈就是4321了,不满足。代码可以用两种,整体入栈和取一半入栈(后半部分入栈和前半部分比较就可以判断)。代码如下:

public static void main(String[] args) {
        ListNode head = new ListNode(1);
        head.add(2);
        head.add(3);
        head.add(2);
        head.add(1);
        System.out.println(head);
        System.out.println(isPalindrome(head));
        System.out.println(isPalindrome2(head));
    }
    //需要一个辅助空间
    public static boolean isPalindrome(ListNode head){
        Stack<ListNode> stack = new Stack<>();
        ListNode cur = head;   //记录指针,取当前节点
        while (cur != null){
            stack.push(cur);
            cur=cur.next;
        }
        while (head != null){  //从头节点开始
            if (head.data != stack.pop().data){//先进后出,相当于从尾开始
                return false;
            }
            head=head.next;
        }
        return true;
    }
    //需要1/2个辅助空间
    public static boolean isPalindrome2(ListNode head){
        if (head == null || head.next == null){
            return true;
        }
        //快慢指针
        ListNode s = head.next;
        ListNode f = head;
        while (f.next != null && f.next.next != null){//慢指针走到了mid
            s = s.next;
            f = f.next.next;
        }
        //定义栈存放后半部分元素
        Stack<ListNode> stack = new Stack<>();
        while (s != null){
            stack.push(s);
            s = s.next;
        }
        while (!stack.isEmpty()){
            if (head.data != stack.pop().data){
                return false;
            }
            head = head.next;
        }
        return true;
    }
 }

在使用1/2个辅助栈的时候用到了快慢指针的概念,用于链表的求中点(链表没有长度不同于线性表的求种点),这个方法常用于链表问题。因为可以求的链表的中点,可以尝试不用栈辅助,将后部分反转,然后用两个头尾指针向中点遍历,判断回文结构,就类似了线性表的回文判断了,代码如下:

 //不需要辅助空间
    public static boolean isPalindrome3(ListNode head){
        if (head == null || head.next == null){
            return true;
        }
        ListNode s = head;
        ListNode f = head;
        while (f.next != null && f.next.next != null){
            s = s.next;  //慢
            f = f.next.next;  //快
        }
        f = s.next;      //保存后半部分
        s.next = null;   //断开
        //反转以f开头的链表
        ListNode p = null;
        while (f != null){
            p = f.next;   //保存next后续节点
            f.next = s;    //convert
            s = f;    //s后移
            f = p; //f后移
        }
        p = s;  //p保存最后一个节点
        f = head;  //从头节点开始
        while (s != null && f != null){
            if (s.data != f.data){   //比较
                return false;
            }
            s = s.next;
            f = f.next;
        }
        return true;
    }

三种方法测试:

[1->2->3->2->1]
true
true
true

合并有序链表

链表分区

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值