【每日算法220514】链表顺位相加和有序链表合并

今日题目

  • 题目1: 把两个长短链表按照顺序每一位相加后返回新的链表(难)
  • 题目2: 把两个有序链表合并后返回新的有序链表(中)

今日心得

  • 直接看算法答案是不能提高算法水平的,算法最重要的就是解题思路而非编码。看了别人的思路去实现会少了最重要的部分。
  • 基本功就是数据结构的基本操作。比如链表结构以及如何遍历链表。如果这些知识都不具备。面试是不可能写出代码的,因为基本人你很难构思出如何遍历链表。

算法编码

链表结构

package linklist;

import java.util.List;

/**
 * @ClassName ListNode
 * @Description 单项链表
 * @Author kouryoushine
 * @Date 2022/5/13 23:23
 * @Version 1.0
 */
public class ListNode {
    int value;
    ListNode next;
    int length;

    public ListNode(int value) {
        this.value = value;
    }


    public static ListNode randListNode(int maxLengh, int maxValue) {
        int first = (int) (Math.random() * maxValue);
        int length = (int) (Math.random() * maxLengh);
        ListNode listNode = new ListNode(first);// first节点
        ListNode tail = listNode;
        for (int i = 0; i < length; i++) {
            int val = (int) (Math.random() * maxValue);
            ListNode node = new ListNode(val);
            tail.next = node;
            tail = node;
        }
        listNode.length=length+1;
        return listNode;

    }


    public void printListNode() {
        ListNode head = this;
        System.out.println(" ");
        System.out.println("print list node ------------------------------");
        while (head != null) {

            System.out.print(head.value);
            head = head.next;
        }

    }

    public int listLength() {
        int length = 0;
        ListNode head = this;
        while (head != null) {
            length++;
            head = head.next;
        }
        return length;

    }



}

两个数字链表相加

package linklist;

import java.util.List;

/**
 * @ClassName AddTwoNumberListNode
 * @Description 两个数字链表相加
 * 链表L: 3->8->9->9->9
 * 链表S: 1->8->3
 * 加法:逐位相加,大于10则进1  ,  4->6->3->0->0->1
 * @Author kouryoushine
 * @Date 2022/5/13 23:25
 * @Version 1.0
 */

//难点在于理解构思如下算法
//对数器不知道怎么写
public class AddTwoNumberListNode {
    public static void main(String[] args) {
        ListNode list1 = ListNode.randListNode(10, 9);
        list1.printListNode();
        ListNode list2 = ListNode.randListNode(10, 9);
        list2.printListNode();
        ListNode result = addTwoNumberList(list1, list2);
        result.printListNode();

    }


    public static ListNode addTwoNumberList(ListNode list1, ListNode list2) {
        //获取
        int length1 = list1.listLength();
        int length2 = list2.listLength();
        ListNode l = length1 > length2 ? list1 : list2; //长链表的头部
        ListNode s = l == list1 ? list2 : list1; //短链表的头
        ListNode curS = s;//初始定位在短链
        ListNode curL = l;//初始定位在长链头部

        ListNode lastL = null;//长节点的最后一个位置
        int carry = 0;//进位非常重要
        //将相加过程分为三个阶段
        //phase1: shortlist not null
        while (curS != null) {
            int sum = curL.value + curS.value + carry;
            carry = sum >= 10 ? 1 : 0;//是否进位  等价于 sum/10
            curL.value = sum % 10; //当前位置的结果
            curS = curS.next; //下标右移动
            curL = curL.next; //下标右移动
        }
        //phase2: longlist not null
        while (curL != null) {  //继续读长数组
            int sum = curL.value + carry;
            carry = sum >= 10 ? 1 : 0;//是否进位
            curL.value = sum % 10; //当前位置的结果
            lastL = curL; //最后一位
            curL = curL.next; //下标右移动
        }

        //phase3: after read all
        if (carry == 1) { //需要把carry作为新的节点添加到尾部
            ListNode lastnode = new ListNode(carry);
            lastL.next = lastnode;
        }

        return l;// 返回长链表(用长链表保存相加的结果)


    }


}

有序链表合并,合并后依然是有序链表

package linklist;

import java.util.ArrayList;

/**
 * @ClassName MergeOrderedListNode
 * @Description 有序链表合并,合并后依然是有序链表
 * * 链表1: 1->3->4->6->7
 * * 链表2: 1->2->6
 * 结果:  1-1-2-3-4-6-6-7
 * @Author kouryoushine
 * @Date 2022/5/14 0:56
 * @Version 1.0
 */
public class MergeOrderedListNode {
    //感觉比较简单,链表遍历熟悉的话
    public static void main(String[] args) {
        ListNode left=new ListNode(1);
        ListNode left1 =new ListNode(3);
        ListNode left2 =new ListNode(4);
        ListNode left3 =new ListNode(6);
        ListNode left4 =new ListNode(7);
        left.next=left1;
        left1.next=left2;
        left2.next=left3;
        left3.next=left4;
        left.printListNode();
        ListNode right=new ListNode(1);
        ListNode right1 =new ListNode(2);
        ListNode right2 =new ListNode(6);
        right.next=right1;
        right1.next=right2;
        right.printListNode();
        ListNode merge = mergeOrderedListNode2(left, right);
        merge.printListNode();

//        ArrayList<ListNode> listNodes = mergeOrderedListNode(left, right);
//        for (int i = 0; i < listNodes.size(); i++) {
//            System.out.println(listNodes.get(i).value);
//        }


    }

    /**
     * 借助队列自己实现了一个版本,队列可以用ArrayList代替
     * @param left
     * @param right
     * @return
     */
    public static ArrayList<ListNode> mergeOrderedListNode(ListNode left, ListNode right) {
        ListNode curL = left;
        ListNode curR = right;
        ArrayList<ListNode> linkedQueue = new ArrayList<>();
        while (curL != null || curR != null) { //任意一个有值就继续读
            int valL = curL != null ? curL.value : Integer.MAX_VALUE; //为空则给最大值
            int valR = curR != null ? curR.value : Integer.MAX_VALUE; //为空则给最大值
            if (valL == valR) {
                linkedQueue.add(curL);
                linkedQueue.add(curR);
                curL = curL.next;
                curR = curR.next;
            } else if (valL > valR) {
                linkedQueue.add(curR);
                curR = curR.next;
            } else {
                linkedQueue.add(curL);
                curL = curL.next;
            }

        }

        return linkedQueue;
    }


    /**
     * 看一下链表的标准算法,比自己想的好很多。看答案很简单,自己构思出来不容易
     */

    public static ListNode mergeOrderedListNode2(ListNode left,ListNode right){
        //选择最小的头部作为最终头部
        ListNode head = left.value<=right.value?left:right;
        ListNode curL= head==left?left.next:left; //跳过头部
        ListNode curR= head==right?right.next:right;  //跳过头部
        ListNode pre =head;//缓存前一个节点

        while (curL!=null && curR!=null){//两边都有值时比较

            if(curL.value<=curR.value){
                pre.next=curL;
                pre=curL;
                curL=curL.next;
            }else {
                pre.next=curR;
                pre=curR;
                curR=curR.next;
            }

            pre.next=curL==null?curR:curL;
        }

        return head;
    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值