【牛客网_刷题记录】链表系列2

11.BM11 链表相加(二)

拿到第一个想法,就是利用stack。因为要先算后面再算前面,但是链表并不能进行随机读取,所以就利用stack的特性,来反着算。但是这样就要用到数组,java的数组实在太麻烦了相比python中的list;

所以我想使用三次头插法。前两次分别逆转输入的两个链表(其实就是BM1中反转链表即可),第三次用头插法建立目标链表。

public class Solution {
    /**
     *
     * @param head1 ListNode类
     * @param head2 ListNode类
     * @return ListNode类
     */
    public ListNode reverselist(ListNode head) {
        ListNode headnode = new ListNode(-1);
        headnode.next = head;
        ListNode cur = head;
        while (cur.next != null) {
            ListNode temp = cur.next;
            cur.next = temp.next;
            temp.next = headnode.next;
            headnode.next = temp;
        }
        return headnode.next;
    }

    public ListNode addInList(ListNode head1, ListNode head2) {
        // write code here
        ListNode head3 = reverselist(head1);
        ListNode head4 = reverselist(head2);
        // System.out.println(head3.val);
        ListNode head5 = new ListNode(-1);
        int flag = 0;//0代表没有进位
        while (head3 != null && head4 != null) {
            ListNode new_node = new ListNode((head3.val + head4.val + flag) % 10);
            System.out.println("当前节点值:" + (head3.val + head4.val + flag) % 10 );
            new_node.next = head5.next;
            head5.next = new_node;
            flag = (head3.val + head4.val + flag) / 10;
            head3 = head3.next;
            head4 = head4.next;
        }
        if (head3 == null) {
            while (head4 != null) {
                ListNode new_node = new ListNode((head4.val + flag) % 10);
                flag = (head4.val + flag) / 10;
                new_node.next = head5.next;
                head5.next = new_node;
                head4 = head4.next;
            }
        } else {
            while (head3 != null) {
                ListNode new_node = new ListNode((head3.val + flag) % 10);
                flag = (head3.val + flag) / 10;
                new_node.next = head5.next;
                head5.next = new_node;
                head3 = head3.next;
            }
        }
        if (flag != 0) {
            ListNode new_node = new ListNode(1);
            new_node.next = head5.next;
            head5.next = new_node;
        }
        return head5.next;
    }
}

此题存在一个陷阱,就是在两个链表都遍历完之后,仍然可能需要进位。比如例题这种情况。

在这里插入图片描述

如果只循环到长的遍历完,那么就会失去第一个节点。

所以在两者遍历完之后,还需要看flag==0?flag是设置的进位标识符,且包含了进位的大小(本题中只要是进位就只能是1)。此题如果用python中的list作为栈来存储数据,然后依据list再来创建新的链表会非常方便,主要是我目前对java中数组的便利操作还不了解。所以使用三次头插法来解决还是挺繁琐。

12.BM12 单链表的排序

第一个想法:这不就是一个冒泡排序吗。。。但是要求时间O(nlogn),所以舍弃。

第二个想法:把链表的存出来,然后Arraylist.sort()。再重新建立链表,这样的时间复杂度是O(n+nlogn) = O(nlogn)。但是不专业,那任何处理链表的值的问题都弄成数组问题了。

第三个就是参考答案给出 采用归并的思路。

归并是1分2,2分4…然后最小比较之后归并----再第二小比较归并—直到和为一个。而每一段(包括只有一个点的时候),其是有序的!所以,问题就变成了两个

1.合并有序链表

2.把一个整个链表,分为两段。其中每一段又是该问题的子问题(直到1个,天然有序)。这样有序的1个和1个归并,就变为了,有序的2个和2个归并…直到整个原来的链表。 而分隔链表可以用,快慢指针:快走2,慢走1,快走到末尾时,慢自然指向中部(因为要涉及断开,可以给慢一个前序指针pre,指向慢的前面结点)

public class Solution {
    /**
     *
     * @param head ListNode类 the head node
     * @return ListNode类
     */
    public ListNode merge(ListNode head1, ListNode head2) {
        if (head1 == null) {
            return head2;
        }
        if(head2==null){
            return head1;
        }
        ListNode p = new ListNode(-1);
        ListNode head3 = p;
        while (head1 != null & head2 != null) {
            if (head1.val < head2.val) {
                head3.next = head1;
                head1 = head1.next;
                head3 = head3.next;
            } else {
                head3.next = head2;
                head2 = head2.next;
                head3 = head3.next;
            }
        }
        if (head1 != null) {
            head3.next = head1;
        } else {
            head3.next = head2;
        }
        return p.next;
    }

    public ListNode sortInList(ListNode head) {
        // write code here
        if (head.next == null) {
            return head;
        }
        ListNode left = new ListNode(-1);
        left.next = head;
        ListNode mid = head;
        ListNode right = head;
        while (right != null && right.next != null) {
            left = left.next;
            mid = mid.next;
            right = right.next.next;
        }
        left.next = null;
        return merge(sortInList(head), sortInList(mid));
    }
}

13.BM13 判断一个链表是否为回文结构

有了前面的铺垫,该题就显得比较简单了。

但是这道题,我犯了一个错误,我直接把head逆置后,和head做比较明显错误,而且还有一个所谓判断回文,是判断值,绝对不能拿结点来比较。

public class Solution {
    /**
     *
     * @param head ListNode类 the head
     * @return bool布尔型
     */
    public ListNode reverse(ListNode head) {
        ListNode headnode = new ListNode(-1);
        headnode.next = null;
        while (head != null) {
            ListNode newnode = new ListNode(head.val);
            newnode.next = headnode.next;
            headnode.next = newnode;
            head = head.next;
        }
        return headnode.next;
    }
    public boolean isPail(ListNode head) {
        // write code here
        ListNode head1 = reverse(head);
        while (head != null) {
            if (head.val != head1.val) {
                return false;
            }
            head = head.next;
            head1 = head1.next;
            continue;
        }
        return true;
    }
}

14.BM14 链表的奇偶重排

这个要求空间复杂度O*(n),时间复杂度 O*(n),主要是空间复杂度很宽松。

弄一个计数count来判断奇偶。然后new两个头结点分别接收奇偶,遍历一次即可完成。

    public ListNode oddEvenList(ListNode head) {
        // write code here
        if (head == null) {
            return head;
        }
        int count = 1;
        ListNode odd = new ListNode(-1);
        ListNode even = new ListNode(-1);
        ListNode m = odd;//奇数
        ListNode n = even;
        while (head != null) {
            if (count % 2 == 0) {
                n.next = head;
                n = n.next;
            } else {
                m.next = head;
                m = m.next;
            }
            count++;
            head = head.next;
        }
        n.next = null;//!!!!一定要注意
        m.next = even.next;
        return odd.next;
    }

注意该题有一个非常值得注意的细节。就是偶数的最后的结点并没有指向null。而是指向了奇数的最后一个结点,随着奇数的最后一个结点指向偶数的第一个结点,就会形成一个环。所以要在最后,加上代码中的那句话,把偶数的最后结点指向null。

15.BM15 删除有序链表中重复的元素-I

就是记住第一个元素,后面依次比较:

相同则直接前序的.next继承当前的.next(也就是相当于删除当前)

不同则pre应该后移到此处(更新pre)

public ListNode deleteDuplicates (ListNode head) {
        // write code here
        if (head == null) {
            return head;
        }
        ListNode pre = head;
        ListNode cur = head.next;
        while (cur != null) {
            if (cur.val == pre.val) {
                pre.next = cur.next;
            } else {
                pre = pre.next;
            }
            cur = cur.next;
        }
        return head;
    }

16.BM16 删除有序链表中重复的元素-II

上题对非空链表的第一个元素不会进行改动,但是本体却会涉及到,所以只要涉及头指针,就要使用使用头结点来便利操作。

当遇到有重复的,就把所有重复的遍历完并且,去掉。

遇到不重复的前面结点next指向该节点。

但是要判断重不重复,必须要判断至少两个结点。

public class Solution {
    /**
     *
     * @param head ListNode类
     * @return ListNode类
     */
    public ListNode deleteDuplicates(ListNode head) {
        // write code here
        if (head == null) {
            return null;
        }
        ListNode headnode = new ListNode(1001);//1001 保证头结点不影响后续
        headnode.next = head;
        ListNode cur = headnode;
        while (cur.next != null && cur.next.next != null) {//因为要比较两个相邻结点,为什么不是cur呢?本体cur起的作用相当于前序结点。
// 1001 1 1 1 2 3 3
// cur  然后cur.next一直往后找排除相同,知道找到2,此时cur直接 = cur.next
            if (cur.next.val == cur.next.next.val) {
                int temp = cur.next.val;
                while (cur.next != null && cur.next.val == temp) {
                    cur.next = cur.next.next;
                }
            } else {
                cur = cur.next;
            }
        }
        return headnode.next;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值