Algorithm: Leetcode 445. 两数相加 II
题目描述:
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.
Example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
解法一:
两个list的长度可能不一样,先用0补齐,再递归。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
int len1 = 0;
for(ListNode p = l1; p != null; p = p.next, len1++);
int len2 = 0;
for(ListNode p = l2; p != null; p = p.next, len2++);
if(len1 > len2) {
for(int i=0; i < len1-len2; i++) {
ListNode p = new ListNode(0);
p.next = l2;
l2 = p;
}
} else if(len1 < len2) {
for(int i=0; i < len2-len1; i++) {
ListNode p = new ListNode(0);
p.next = l1;
l1 = p;
}
}
ListNode ans = new ListNode(0);
int c = add(l1, l2, ans);
if(c != 0) {
ListNode p = new ListNode(c);
p.next = ans;
ans = p;
}
return ans;
}
public int add(ListNode a, ListNode b, ListNode result) {
int sum = 0;
if(a.next == null && b.next == null) {
sum = a.val + b.val;
} else {
result.next = new ListNode(0);
sum = a.val + b.val + add(a.next, b.next, result.next);
}
result.val = sum % 10;
return sum / 10;
}
}
解法二:将输入反转,链表的开头变成最低位,从最低位开始,逐位相加,最后把结果反转。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
l1 = reverse(l1);
l2 = reverse(l2);
return addTwoNumbers1(l1, l2);
}
private ListNode reverse(ListNode l) {
if(l == null) {
return null;
}
ListNode p1 = l;
ListNode p2 = p1.next; // nullable
ListNode p3 = p2 == null ? null : p2.next; // nullable
p1.next = null;
while(p2 != null) {
p2.next = p1;
p1 = p2;
p2 = p3;
p3 = p3 == null ? null : p3.next;
}
return p1;
}
private ListNode addTwoNumbers1(ListNode l1, ListNode l2) {
if(l1 == null) {
return l2;
}
if(l2 == null) {
return l1;
}
ListNode result = new ListNode(0);
ListNode p = result;
int carry = 0;
while(l1 != null || l2 != null || carry != 0) {
int sum = (l1 == null ? 0 : l1.val) + (l2 == null ? 0 : l2.val) + carry;
carry = sum / 10;
p.next = new ListNode(sum % 10);
p = p.next;
l1 = l1 == null ? null : l1.next;
l2 = l2 == null ? null : l2.next;
}
result = result.next;
return reverse(result);
}
}
解法三:不改变输入,用栈(或LinkedList)保存输入,利用栈后进先出的特点,从低位开始加,最后将结果反转。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
Stack<Integer> s1 = pushToStack(l1);
Stack<Integer> s2 = pushToStack(l2);
int carry = 0;
ListNode result = new ListNode(0);
ListNode p = result;
while(!s1.empty() || !s2.empty() || carry != 0) {
int a = s1.empty() ? 0 : s1.pop();
int b = s2.empty()? 0 : s2.pop();
int sum = a + b + carry;
p.next = new ListNode(sum % 10);
p = p.next;
carry = sum / 10;
}
return reverse(result.next);
}
private Stack<Integer> pushToStack(ListNode l1) {
Stack<Integer> s1 = new Stack<>();
while(l1 != null) {
s1.push(l1.val);
l1 = l1.next;
}
return s1;
}
private ListNode reverse(ListNode l) {
if(l == null) {
return null;
}
ListNode p1 = l;
ListNode p2 = p1.next; // nullable
ListNode p3 = p2 == null ? null : p2.next; // nullable
p1.next = null;
while(p2 != null) {
p2.next = p1;
p1 = p2;
p2 = p3;
p3 = p3 == null ? null : p3.next;
}
return p1;
}
}
三种解法中,反转输入的链表是最快的。
Review:EaaS: Everything-as-a-Service
文章阐述了传统的服务和现在流行的SOA、微服务等各自的特点,抛出了未来“万物都是服务”这么一个论点。
文中阐述了SOA和微服务架构的共同点和主要的区别。首先,两种的共同点是都秉承了模块化的设计理念:高内聚、低耦合。不同点:SOA主要是在应用层面实现模块化,而数据库等组建还是共用的。而微服务则是每个组建都独立,一个微服务实例从上到下自成一体。
文章后面还介绍了IaaS、Paas、SaaS等概念,用一张图清晰地展示了这些不同“服务”之间的区别。
[外链图片转存失败(img-XHW0ntDs-1562044526151)(https://cdn-images-1.medium.com/max/800/1*OIXF4l8XLNTkOcdSVuX65Q.png)]
Tip:
在用hibernate的ORM时,如果A类和B类之间通过@ManyToOne关联,当持久化A类时,要求B类先持久化,否则会报错:
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing
即数据库里面要先有One后有Many,因为ManyToOne实际上是一个外键约束。
Share:关于HashMap容量的初始化,还有这么多学问
HashMap的构造方法支持传入初始容量,但是并不是直接将元素个数作为初始容量就OK了。
HashMap并不一定采用我们传入的初始容量,而是寻找一个大于它且最接近的2的N次幂。并且,HashMap中有个负载因子(loadFactor),默认值是0.75,意思是当map中的元素个数达到 当前容量负载因子 时,就会发生扩容。举个例子,我们的元素个数是16,当我们把初始容量设为16时,元素个数达到 160.75=12 个时,就会发生扩容,这显然不是我们想要的。我们需要将初始容量设为
16 / 0.75 + 1 = 22 才能保证所有元素都放进map并且不会发生扩容(当然了,jdk不会直接使用22,而是会向上寻找最近的2的N次幂,也就是32)。
在实际使用时,对于我们能够确切知道元素个数的情况下,尤其是在一些性能敏感的场景下,或者是在循环体内部,尽量计算好合适的初始容量,避免扩容带来性能损失。
Google的guava 21版本之后的集合工具类都提供了类似这样的api
Maps.newHashMapWithExpectedSize(int expectedSize)
我们只要传入实际的元素个数就行了,内部会完成上述计算。