阿亮的算法之路——2. 两数相加

2024-01-07 02:59
文章标签 算法 相加 阿亮

本文主要是介绍阿亮的算法之路——2. 两数相加,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

题目描述
我一开始的思路是:遍历这两个链表,将这两个数还原回去,然后做运算,将运算完的结果再按照要求逆序取出来,做成一个链表。实际上应该是可行的,

初次尝试

但是:
提交记录1
我还原回去的数用了一个int类型的变量来接收,但是当第1559个用例时,这个还原回去的数就已经超过了int类型了……迫于无奈,我将类型换成了long类型,我想着这下应该够了把,结果:提交记录2
第1560个用例,直接来了这么长,好像有30位,long类型范围好像是在20位左右,头大,难道换成继续换成double类型的?要是他来个几百位怎么办?换思路换思路,而且是时候换成double好像也无法实现。

    public static ListNode addTwoNumbers(ListNode l1, ListNode l2){double l1Num = getNum(l1);double l2Num = getNum(l2);double sum = l1Num + l2Num;ListNode temp = new ListNode((int) (sum%10));ListNode re = temp;sum = Math.floor(sum/10);while (sum > 0){int each = (int) (sum % 10);System.out.println(each);ListNode listNode = new ListNode(each);temp.next = listNode;temp = listNode;sum = Math.floor(sum/10);}return re;}public static double getNum(ListNode l1){double sum = 0;int count = 0;while (l1 != null){int val = l1.val;sum +=  val*Math.pow(10,count);l1 = l1.next;count++;}System.out.println(sum);return sum;}

更换思路

之前的思路被否决的之后,就思考:为什么要把这个两个数复原回去呢?复原回去之后还要重新遍历。那就不复原,直接遍历这两个链表,在遍历的过程中,将对应位置的数加起来。

这个思路是可行的,但是要考虑边界情况和进位情况,我按照这个思路,写出了初代版本,然后各种提交调试,最后通过了

        boolean carry = false; //进位标志,注意要重置ArrayList<Integer> l1ArrayList = new ArrayList<>();while (l1 != null){l1ArrayList.add(l1.val);l1 = l1.next;}int size1 = l1ArrayList.size();ArrayList<Integer> l2ArrayList = new ArrayList<>();while (l2 != null){l2ArrayList.add(l2.val);l2 = l2.next;}int size2 = l2ArrayList.size();int firstSum = l1ArrayList.get(0)+l2ArrayList.get(0);ListNode temp = new ListNode(firstSum%10);ListNode re = temp;if (firstSum >=10){carry = true;if (size1 ==1 && size2 == 1){ temp.next = new ListNode(firstSum/10); }}for (int i = 1,j = 1; i<size1 || j<size2; i++,j++){int num1 ;if (i >= size1) { num1 = 0; }else { num1= l1ArrayList.get(i); }int num2 ;if (j >= size2) { num2 = 0; }else { num2 = l2ArrayList.get(j); }int sum = num1 + num2;ListNode eachTemp = new ListNode(sum%10);if (carry){if (sum%10 +1 < 10){eachTemp = new ListNode(sum%10+1);carry = false;}else{eachTemp = new ListNode(0);carry = true;}}temp.next = eachTemp;temp = eachTemp;if (sum >= 10){ carry = true; }}if (carry){ temp.next = new ListNode(1); }return re;

效果不是很理想
提交结果

优化

我透,我是个傻逼啊,我为什么要先将两个链表遍历一遍放入集合中,再从集合中取?直接在遍历的时候去不就可以了??这不是脱了裤子放屁吗

        boolean carry = false; //进位标志,注意要重置int firstNum = l1.val + l2.val;ListNode temp = new ListNode(firstNum%10);ListNode re = temp;l1 = l1.next; l2 = l2.next;if (firstNum >= 10){carry = true;if (l1 == null && l2 == null){ temp.next = new ListNode(firstNum/10); }}while (l1 != null || l2 != null){int num1;if (l1 == null){ num1 = 0; }else{ num1 = l1.val; }int num2;if (l2 == null){ num2 = 0; }else{ num2 = l2.val; }int sum = num1 + num2;ListNode eachTemp = new ListNode(sum%10);if (carry){if (sum % 10 < 9){eachTemp = new ListNode(sum%10+1);carry = false;}else{eachTemp = new ListNode(0);carry = true;}}temp.next = eachTemp;temp = eachTemp;if (sum >= 10){ carry = true; }if (l1 != null) { l1 = l1.next; }if (l2 != null) { l2 = l2.next; }}if (carry){ temp.next = new ListNode(1); }return re;

省掉了两次遍历链表,提交结果
提交结果2果然,效果明显的提升啊,估计我当时脑子抽了。我最开始好像想的是,因为题目将这个数逆置了,所以不能直接遍历,从尾部开始遍历,又因为单链表无法倒序遍历,所以才先正序遍历,存入了集合中。想多了想多了

大佬思路

官方给出的思路也是我上面那种思路,但是他细节方面除了的很好,代码量是我的四分之一,完成的功能却是一样的。细节主要有:

  1. 他用了一个哑节点,用来处理头结点和尾节点,而我是分别特殊处理的
  2. 他用了一个0和1的数值来处理进位问题,而我用的是一个布尔类型的标记。用数值类型,可以直接加上这个数值,而用布尔类型,需要判断,再决定加或不加,无形之中增加了工作量。

代码

  ListNode dummyHead = new ListNode(0);ListNode p = l1, q = l2, curr = dummyHead;int carry = 0;while (p != null || q != null) {int x = (p != null) ? p.val : 0;int y = (q != null) ? q.val : 0;int sum = carry + x + y;carry = sum / 10;curr.next = new ListNode(sum % 10);curr = curr.next;if (p != null) p = p.next;if (q != null) q = q.next;}if (carry > 0) {curr.next = new ListNode(carry);}return dummyHead.next;

大佬提交优秀!!!

这篇关于阿亮的算法之路——2. 两数相加的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/578508

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

最大公因数:欧几里得算法

简述         求两个数字 m和n 的最大公因数,假设r是m%n的余数,只要n不等于0,就一直执行 m=n,n=r 举例 以18和12为例 m n r18 % 12 = 612 % 6 = 06 0所以最大公因数为:6 代码实现 #include<iostream>using namespace std;/