数据结构-链表刷题集(长期更新)

本文介绍了如何使用模拟竖式加法的方法解决LeetCode上的两数之和问题,以及链表反转和指定区间链表翻转的算法实现,重点在于递归和数组/链表的操作技巧。
摘要由CSDN通过智能技术生成

1. leetcode 2 两数之和

1.1 解法一

题目及其相关实例如下
在这里插入图片描述
在这里插入图片描述
要做这个题,首先我们要学会模拟竖式的加法,我们知道即使是java基本数据中最大的long类型范围也是有限的,那如果超出范围了我们该怎么办呢,我们就需要用字符串来模拟这个加法的过程
思路分析:
1.将字符串转化为字符数组进行存储(toCharArray方法)
2.把字符数组逆序操作变为数字数组(逆序的原因是模拟竖式对齐)
3.创建一个ret数组用来保存逐个相加的结果
4.最后逆序输出ret数组就是最终的答案
代码实现如下

public static void addNumber(String s1,String s2){
        //这是我们的准备工作,先把字符串转换为字符数组,创建的arr1数组用来存放c1中的数字,arr2数组用来存放c2中的数字,创建一个返回数组用来输出结果
        char[] c1 = s1.toCharArray();
        char[] c2 = s2.toCharArray();
        int len1 = c1.length;
        int len2 = c2.length;
        int[] arr1 = new int[len1];
        int[] arr2 = new int[len2];
        int maxlen = len1 > len2 ? len1 : len2;
        int minlen = len1 > len2 ? len2 : len1;
        int[] ret = new int[maxlen + 1];

        //下面的工作是把字符串进行翻转并进行存储,用来模拟竖式相加对齐
        for(int i = len1 - 1; i >= 0; --i){
            arr1[len1 - 1 -i] = c1[i] - '0';
        }
        for(int i = len2 - 1; i >= 0; --i){
            arr2[len2 - 1 - i] = c2[i] - '0';
        }

        //下面我们模拟竖式的相加
        for(int i = 0; i < maxlen; ++i){
            if(i < minlen){
                ret[i + 1] = (ret[i] + arr1[i] + arr2[i]) / 10;
                ret[i] = (ret[i] + arr1[i] + arr2[i]) % 10;
            }else if(minlen == len1){
                ret[i + 1] = (ret[i] + arr2[i]) / 10;
                ret[i] = (ret[i] + arr2[i]) % 10;
            }else{
                ret[i + 1] = (ret[i] + arr1[i]) / 10;
                ret[i] = (ret[i] + arr1[i]) % 10;
            }
        }
		//因为是逆序的,需要判断最后一个是不是0
        if(ret[ret.length - 1] == 0) {
            ret = Arrays.copyOf(ret, ret.length - 1);
        }

        for(int i = 0; i < ret.length / 2; ++i){
            int temp = ret[i];
            ret[i] = ret[ret.length - 1 - i];
            ret[ret.length - 1 -i] = temp;
        }

        System.out.println(Arrays.toString(ret));
    }

有了上面的铺垫,我们的两数相加其实就是这个原理,由于我们不知道具体链表的长度(可以整一个size方法,但是没必要),我们直接用顺序表来代替数组来进行操作,依然是模拟竖式相加,最后逐个new新节点进行串联即可(创建一个虚拟的节点进行连接)
代码实现如下

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        if(l1 == null || l2 == null){
            return null;
        }
         //我们通过创建一个集合类解决吧
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();

        //开始遍历我们的链表
        ListNode cur = l1;
        while(cur != null) {
            int temp = cur.val;
            list1.add(temp);
            cur = cur.next;
        }
        ListNode curN = l2;
        while(curN != null) {
            int temp = curN.val;
            list2.add(temp);
            curN = curN.next;
        }

        //上面的那一步其实就相当于是把字符存入数组
        int len1 = list1.size();
        int len2 = list2.size();
        int maxlen = len1 > len2 ? len1 : len2;
        int minlen = len1 > len2 ? len2 : len1;
        int[] ret = new int[maxlen + 1];


        //跟上面的模拟不一样的这个是,这个本来就是逆序的,所以不用进行反转
        //开始模拟竖式相加的求和操作
        for(int i = 0; i < maxlen; ++i){
            if(i < minlen){
                ret[i + 1] = (ret[i] + list1.get(i) + list2.get(i)) / 10;
                ret[i] = (ret[i] + list1.get(i) + list2.get(i)) % 10;
            }else if(minlen == len1){
                ret[i + 1] = (ret[i] + list2.get(i)) / 10;
                ret[i] = (ret[i] + list2.get(i)) % 10;
            }else{
                ret[i + 1] = (ret[i] + list1.get(i)) / 10;
                ret[i] = (ret[i] + list1.get(i)) % 10;
            }
        }

        //模拟竖式相加成功,现在看看最后一位是不是0(因为是倒叙求和的)
        if(ret[ret.length - 1] == 0){
            ret = Arrays.copyOf(ret,ret.length - 1);
        }

        //最后采用虚拟节点法把这ret中的节点都连接起来即可
        ListNode head = new ListNode(-1);
        cur = head;
        for(int i = 0; i < ret.length ; ++i){
            ListNode node = new ListNode(ret[i]);
            cur.next = node;
            cur = cur.next;
        }
        
        //最后返回虚拟节点的下一个位置
        return head.next;
    }
}

2. 链表反转

我们的代码翻转用的是头插法,特殊点是在翻转完毕之后
我们的temp指针指向的新的头节点,我们的cur为空指针
代码实现如下

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode temp = null;
        ListNode cur = head;
        while(cur != null){
            ListNode curN = cur.next;
            cur.next = temp;
            temp = cur;
            cur = curN;
        }
        return temp;
    }
}

3. 指定区间的链表翻转

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值