【牛客面试必刷TOP101】Day21.BM11 链表相加(二)和BM12 单链表的排序

作者简介:大家好,我是未央;

博客首页:未央.303

系列专栏:牛客面试必刷TOP101

每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!!!

文章目录

前言

一、BM11 链表相加(二)

题目描述

题目解析

二、BM12 单链表的排序

题目描述

         题目解析

总结



前言


一、BM11 链表相加(二)

题目描述

描述:

假设链表中每一个节点的值都在 0 - 9 之间,那么链表整体就可以代表一个整数。

给定两个这种链表,请生成代表两个整数相加值的结果链表。

数据范围:0≤n,m≤1000000,链表任意值 0≤val≤9
要求:空间复杂度 O(n),时间复杂度 O(n)


例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。


示例1:


示例2:



题目解析

解题思路:

方法:反转链表法(推荐使用)


思路:

既然链表每个节点表示数字的每一位,那相加的时候自然可以按照加法法则,从后往前依次相加。但是,链表是没有办法逆序访问的,这是我们要面对第一只拦路虎。解决它也很简单,既然从后往前不行,那从前往后总是可行的吧,将两个链表反转一下:

while(cur != null){
    //断开链表,要记录后续一个
    ListNode temp = cur.next;
    //当前的next指向前一个
    cur.next = pre; 
    //前一个更新为当前
    pre = cur; 
    //当前更新为刚刚记录的后一个
    cur = temp; 
}

即可得到个十百千……各个数字从前往后的排列,相加结果也是个位在前,怎么办?再次反转,结果不就正常了。


解题步骤:

  • step 1:特殊情况。任意一个链表为空,返回另一个链表就行了,因为链表为空相当于0,0加任何数为0,包括另一个加数为0的情况。
  • step 2:相继反转两个待相加的链表,反转过程可以参考BM1反转链表。
  • step 3:设置返回链表的链表头,设置进位carry=0.
  • step 4:从头开始遍历两个链表,直到两个链表节点都为空且carry也不为1. 每次取出不为空的链表节点值,为空就设置为0,将两个数字与carry相加,然后查看是否进位,将进位后的结果(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历。
  • step 5:返回前将结果链表再反转回来。

图示说明:


代码编写:


import java.util.*;
public class Solution {
    //建立一个ReverseList()方法函数用来反转链表操作。
    //反转链表
    public ListNode ReverseList(ListNode pHead) {
        if (pHead == null)
            return null;
        ListNode cur = pHead;
        ListNode pre = null;
        while (cur != null) {
            //断开链表,要记录后续一个
            ListNode temp = cur.next;
            //当前的next指向前一个
            cur.next = pre;
            //前一个更新为当前
            pre = cur;
            //当前更新为刚刚记录的后一个
            cur = temp;
        }
        return pre;
    }

    public ListNode addInList (ListNode head1, ListNode head2) {
        //step 1:特殊情况。任意一个链表为空,返回另一个链表就行了,因为链表为空相当于0,0加任何数为0,包括另一个加数为0的情况。
        if (head1 == null)
            return head2;
        if (head2 == null)
            return head1;
        //step 2:相继反转两个待相加的链表,反转过程可以参考BM1反转链表。
        head1 = ReverseList(head1);
        head2 = ReverseList(head2);
        //step 3:设置返回链表的链表头,设置进位carry=0.
        //添加表头
        ListNode res = new ListNode(-1);
        ListNode head = res;
        //进位符号
        int carry = 0;
        //step 4:从头开始遍历两个链表,直到两个链表节点都为空且carry也不为1. 每次取出不为空的链表节点值,为空就设置为0,将两个数字与carry相加,然后查看是否进位,将进位后的结果(对10取模)加入新的链表节点,连接在返回链表后面,并继续往后遍历。
        //只要某个链表还有或者进位还有
        while (head1 != null || head2 != null || carry != 0) {
            //链表不为空则取其值
            int val1 = head1 == null ? 0 : head1.val;
            int val2 = head2 == null ? 0 : head2.val;
            //相加
            int temp = val1 + val2 + carry;
            //获取进位
            carry = temp / 10;
            temp %= 10;
            //添加元素
            head.next = new ListNode(temp);
            head = head.next;
            //移动下一个
            if (head1 != null)
                head1 = head1.next;
            if (head2 != null)
                head2 = head2.next;
        }
        //step 5:返回前将结果链表再反转回来。
        return ReverseList(res.next);
    }
}

二、BM12 单链表的排序

题目描述

描述:

给定一个节点数为n的无序单链表,对其按升序排序。

数据范围:0<n≤100000,保证节点权值在[−109,109]之内。

要求:空间复杂度 O(n),时间复杂度O(nlogn)


示例1:


示例2:


题目解析

解题思路:

方法:转化为数组排序(扩展思路)


思路:

链表最难受的就是不能按照下标访问,只能逐个遍历,那像排序中常规的快速排序、堆排序都不能用了,只能用依次遍历的冒泡排序、选择排序这些。但是这些O(n2)复杂度的排序方法太费时间了,我们可以将其转化成数组后再排序。


解题步骤:

  • step 1:遍历链表,将节点值加入数组。
  • step 2:使用内置的排序函数对数组进行排序。
  • step 3:依次遍历数组和链表,按照位置将链表中的节点值修改为排序后的数组值。

代码编写:


import java.util.*;
public class Solution {
    public ListNode sortInList (ListNode head) {
        ArrayList<Integer> nums = new ArrayList();
        ListNode p = head;
        //step 1:遍历链表,将节点值加入数组。
        while (p != null) {
            nums.add(p.val);
            p = p.next;
        }
        p = head;
        //step 2:使用内置的排序函数对数组进行排序。
        Collections.sort(nums);
        //step 3:依次遍历数组和链表,按照位置将链表中的节点值修改为排序后的数组值。
        for (int i = 0; i < nums.size(); i++) {
            //将数组元素依次加入链表
            p.val = nums.get(i);
            p = p.next;
        }
        return head;
    }
}

总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值