最近开始刷LeetCode,为了以后的工作做准备。
1. Add Two Numberes
题目要求:输入两个链表,分别为:
l1 : 2 >- 4 >- 3
l2 : 5 >- 6 >- 4
要求输出结果为:
l3 : 7 >- 0 >- 8
分析:通过观察可以发现,其实就是从左向右对应位置相加,如果大于10,就像右进一位。
- 下面给出代码
// 定义链表节点
class ListNode{
int val;
ListNode next;
ListNode(int x){ val = x;}
}
public class ListNodeTest {
public static void main(String[] args) {
/* 定义三个链表节点 然后给l1 l2添加节点
* l1 2 >- 4 >- 3
* l2 5 >- 6 >- 4
* */
ListNode l1 = new ListNode(2);
ListNode l2 = new ListNode(5);
// 这里的l3最后用来输出计算后的节点
ListNode l3 = new ListNode(0);
// 将l1 和 l2 以及 l3链表的第一个节点赋值给p 、q、curr
ListNode p = l1 , q = l2 ,curr = l3;
l1.next = new ListNode(4);
l1.next.next = new ListNode(3);
l2.next = new ListNode(6);
l2.next.next = new ListNode(4);
// 设置标志位, 用来判断是否对应位置相加,超过了10,
// 若超过10 就设置为1
int flag = 0;
while(p != null || q != null) {
// 为了防止两个链表的长度不一样 防止出现 null 与数字的相加 在这里将链表值为null设置为0 用于计算
int x = (q != null) ? q.val : 0;
int y = (p != null) ? p.val : 0;
int sum = x + y + flag;
// 通过计算的值 来判断是否需要进位
flag = sum / 10;
// 给curr的添加下一个节点
// 注意这里和l3的区别
curr.next = new ListNode(sum % 10);
// 添加完节点之后 更新指针 指向当前节点
curr = curr.next;
// 这里一定要添加if判断 之前没有添加 出现空指针异常
// ? 因为如果q已经为null 那么q.next就不存在
if(q != null) q = q.next;
if(p != null) p = p.next;
}
// 如果这里flag大与0 是因为两个链表的尾节点相加大于10 又进了一位
// 因此要继续添加一个节点 用来存放进的那一位
if(flag > 0) {
curr.next = new ListNode(flag);
}
while(l3.next != null) {
System.out.print(l3.next.val + ">-");
if(l3 != null) {
l3 = l3.next;
}
}
}
}
总结
(1)由于太久没看数据结构,忘记了对列表的定义。这里首先要理解链表的数据结构。也就明白了为什么要定义q、p、curr。
(2)这里要考虑到,如果输入的两个链表不等长,那么就会出现一个为空的情况,这样是没有办法进行相加的。因此,需要将为空的那个链表节点赋值成0用于计算。
(3)在更新链表节点的时候,一定要进行判断当前节点是否为空,如果不加判断,就有可能出现空指针异常。
(4)最后计算完毕后,一定要对进位标志flag进行判断,防止两个链表的最后一位相加后,超过10,继续向又进一位。
2. Two Sum
要求:给一个整型数组 [2, 7, 11, 15],一个整数 9
输出结果为:[0 , 1] 注:假设只有一个答案
分析:这是刷的第一道题,比较简单,就是在数组中找到两个数相加等于目标数,找到后,将这两个数的指数按照由大到小排列返回。比较容易想到的方法就是利用一个双重for循环。
- 双重的for循环的代码就不给出了,下面先写出将双重for循环降低为两个for循环的代码
public class Two_Sum {
public static void main(String[] args) {
int[] a = {2 ,7 ,11 ,15};
int target = 9;
int[] answer = twoSum(a , target);
for (int i : answer) {
System.err.println(i);
}
}
public static int[] twoSum(int[] a ,int target) {
Map<Integer, Integer> map = new HashMap<Integer,Integer>();
// 将数组a中的元素以及索引添加到Map中
for(int i = 0; i < a.length; i++) {
map.put(a[i] ,i );
}
// 将数组放入到集合中后,
for(int i = 0; i < a.length; i++) {
int complement = target - a[i];
if(map.containsKey(complement) && map.get(complement) != i) {
return new int[] {i , map.get(complement)};
}
}
// 当走到这里时,就代表没有这个数组中没有满足题目要求的答案
// 此时可以抛出一个异常
throw new IllegalArgumentException("没有找到满足题目要求的答案!");
}
}
总结:
(1)不得不佩服该方法的技巧性,使用双重for循环的时间复杂度为O(n²),降低为两个for循环之后,算法的时间复杂度为O(n),但空间复杂度也为O(n)。
(2)map中将value的值设置为数组中的索引,方便后面利用map的方法获取到其值。
(3)最后,还要考虑不满足条件的处理,这里通过异常处理。
(4)算是个知识盲点吧,java基础不牢固,map中key和value只能存对象,不能存基本数据类型。
2 . 上面的代码还可以在进行优化,将其减少成一个for循环。
public static void main(String[] args) {
int[] a = {2 ,7 ,11 ,15};
int target = 9;
int[] answer = twoSum02(a , target);
for (int i : answer) {
System.err.println(i);
}
}
public static int[] twoSum02(int[] a ,int target) {
Map<Integer, Integer> map = new HashMap<Integer,Integer>();
// 将数组放入到集合中后,
for(int i = 0; i < a.length; i++) {
int complement = target - a[i];
if(map.containsKey(complement)) {
return new int[] {map.get(complement), i};
}
map.put(a[i], i);
}
总结:
(1)代码牛逼
(2)一定注意返回索引的顺序