一个人对行为本身的意愿和他对于行为带来的结果的意愿,两者都是一个人最终是否行动的动机因素。
每一个因素都有自身的拉力,若两个力是相对的,则其中更强大的因素将会决定一个人的行为。
1. 加法运算
真正在刷题的过程中,我们只需要记住几点即可:
- 低位到高位,逐位求和的算法为:sum = x + y + carry.( x和y 分别来表示每位的数值,carry 表示进位,默认为0)
- 当前位的值:cur = sum % 10
- 进位carry的值:carry = sum / 10;
PS:因为是从低位 ->高位,所以需要注意结果是否需要翻转,通常可借助于:
-
反转操作:
- StringBuilder/ StringBuffer 的 reverse();
- Collections.reverse();
-
头插法思想:
- LinkedList的addFirst(value) ;
- 链表的头插法;
- ArrayList的add(0, value)
-
栈
下面我们通过这个模拟操作,来解决Leetcode的相关问题。
415. 字符串相加
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。
1. 常规写法
public String addStrings(String num1, String num2) {
StringBuilder sb = new StringBuilder();
int i = num1.length() -1;
int j = num2.length() -1;
int carry = 0;
while(i >= 0 || j >= 0 || carry > 0){
// 字符0就是48
int x = (i >= 0) ? num1.charAt(i--) - '0' : 0;
int y = (j >= 0) ? num2.charAt(j--) - '0' : 0;
int sum = (x + y + carry);
int curVal = sum % 10; //当前位的值
sb.append(curVal);
carry = sum / 10;// 处理进位的值
}
return sb.reverse().toString();
}
2. 精炼写法
本质上没有任何区别,只是在熟练之后,我们往往会在不破坏代码可读性的情况,对代码做出优化。
public String addStrings(String num1, String num2) {
StringBuilder sb = new StringBuilder();
int i = num1.length() -1;
int j = num2.length() -1;
int carry = 0;
while(i >= 0 || j >= 0 || carry > 0){
// 字符0就是48
carry += (i >= 0) ? num1.charAt(i--) - '0' : 0;
carry += (j >= 0) ? num2.charAt(j--) - '0' : 0;
sb.append(carry % 10);
carry /= 10;// 处理进位的值
}
return sb.reverse().toString();
}
2. 链表中的两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
In a word, 求数据结构之链表的两数之和问题。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int carry = 0;
ListNode dummy = new ListNode(-1);
ListNode cur = dummy;
while(l1 != null || l2 != null || carry != 0){
carry += (l1 != null) ? l1.val : 0;
carry += (l2 != null) ? l2.val : 0;
cur.next = new ListNode(carry % 10);
cur = cur.next;
carry /= 10;
if(l1 != null){
l1 = l1.next;
}
if(l2 != null){
l2 = l2.next;
}
}
return dummy.next;
}
445. 链表中的两数相加 II
闲暇之余,可以顺手解决 剑指 Offer II 025. 链表中的两数相加
给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:如果输入链表不能翻转该如何解决?
人生苦短,我要翻转 , 感兴趣的可以点进去看一下。
进阶解法
不让我们翻转,那我们就采用前面介绍的一些手段来达到翻转的效果。
需要注意的是,此题有两处需要翻转:
- 操作数的链表翻转 ;
- 结果需要翻转;
最佳方案; 数据结构(栈) + 链表的头插法。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
// 第一步:入栈操作
Stack<Integer> s1 = new Stack<>();
Stack<Integer> s2 = new Stack<>();
while(l1 != null){
s1.push(l1.val);
l1 = l1.next;
}
while(l2 != null){
s2.push(l2.val);
l2 = l2.next;
}
// 头插法
ListNode head = null;
int carry = 0;
while(!s1.isEmpty() || !s2.isEmpty() || carry > 0){
carry += (s1.isEmpty()) ? 0 : s1.pop();
carry += (s2.isEmpty()) ? 0 : s2.pop();
ListNode node = new ListNode(carry % 10);
node.next = head;
head = node;
carry /= 10;
}
return head;
}
43. 字符串相乘
public String multiply(String num1, String num2) {
if(num1.equals("0") || num2.equals("0")){
return "0";
}
if(num1.equals("1")){
return num2;
}
if(num2.equals("1")){
return num1;
}
String result = "0";
int len1 = num1.length();
int len2 = num2.length();
for(int i = len2 - 1; i >= 0;i--){
int carry = 0;
StringBuilder tmp = new StringBuilder();
//补0
for(int j = 0;j < len2-1 - i;j++){
tmp.append(0);
}
int n2 = num2.charAt(i) - '0';
for(int j = len1 - 1; j >= 0|| carry != 0; j--){
int n1 = j < 0 ? 0:num1.charAt(j) - '0';
int product = (n1 * n2 +carry) % 10;
tmp.append(product);
carry = (n1 * n2+carry)/ 10;
}
result = addStrings(result,tmp.reverse().toString());
}
return result;
}
// 实现字符串相加的功能
public String addStrings(String num1,String num2){
StringBuilder sb = new StringBuilder();
int carry = 0;
int i1 = num1.length() - 1;
int i2 = num2.length() - 1;
while(i1 >= 0 || i2 >= 0 || carry > 0){
carry += i1 >= 0 ? (num1.charAt(i1--) - '0'):0;
carry += i2 >= 0 ? (num2.charAt(i2--) - '0'):0;
sb.append(carry % 10);
carry /= 10;
}
return sb.reverse().toString();
}
```