LeetCode刷题笔记------Add Two Numbers 和 Two Sum

最近开始刷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循环。

  1. 双重的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)一定注意返回索引的顺序

猜你喜欢

转载自blog.csdn.net/Time__Lc/article/details/88540849