leetcode top100 - 02

2. 两数相加

  1. 转换成数字进行运算,最后转换成链表。可能会出现溢出的情况。
    因为无论是int还是long类型表达的数字长度是有限的,而链表的长度是可以无限追加的。
  2. 解释是干扰你的,其实就是依次从低位到高位的进位过程

笔试思路

把链表依次填充到数组中,数组容易操作,然后逐位进行加法运算;

面试思路

使用链表的思路去解决。

  1. 注意考虑 链表长度不一样的情况,短链表需要一直陪跑,补充0。
    只要有一个不为空,则……
    while(l1 != null || l2 != null){

    }

  2. 最后一位可能出现进位,需要补1

  3. n%10,n/10的玩法

  • 扩展
  1. 队列和栈的常用方法巧记

    压栈弹栈,入队拉出队

    栈的常用方法:
    push:推入,类似于“扑通”声。
    pop:弹出,类似于“砰”的一声。
    peek:窥视,类似于“皮皮”声。
    isEmpty:判断是否为空,类似于“是不是空”的疑问。

    队列的常用方法:
    offer:入队,类似于“哦菲儿”声。
    poll:出队,类似于“咕噜”声。
    peek:查看队首元素,类似于“皮皮”声。
    isEmpty:判断是否为空,类似于“是不是空”的疑问。

    以下是一些将谐音词汇和栈、队列联系起来的方法:

    栈的谐音词汇可以联系到“扑通”声和“砰”的一声,这是因为栈的特点是后进先出,类似于一个物体被推入栈中时发出的声音,以及从栈中弹出物体时发出的声音。

    队列的谐音词汇可以联系到“哦菲儿”和“咕噜”的声音,这是因为队列的特点是先进先出,类似于一个物体被推入队列中时发出的声音,以及从队列中弹出物体时发出的声音。

    栈和队列的 peek 方法可以联系到“皮皮”声,因为这个方法用于查看栈顶或队首的元素,类似于在看一张扑克牌的牌面。

    栈和队列的 isEmpty 方法可以联系到“是不是空”的疑问,因为这个方法用于判断栈或队列是否为空。当栈或队列为空时,就可以想象自己在问“是不是空呢?”这样可以更容易地记忆这个方法。

    通过将谐音词汇和栈、队列联系起来,可以帮助我们更加轻松地记忆栈和队列的常用方法。

  2. 遍历链表的方法优化
    在 while 循环中使用了 l1.next 和 l2.next,导致最后一个节点没有被处理。另外,在对链表进行遍历时,应该使用 while (node != null) 循环,而不是 do-while 循环。

    用while循环来替代do-while循环,这样就不需要判断链表是否为空或者只有一个节点了;

        // 遍历链表
        while (l1 != null) {
            l1Stack.push(l1.val);
            l1 = l1.next;
        }
    
  3. 把队列数据压进链表的方法优化

    老代码

        ListNode res = new ListNode(queue1.poll());
        ListNode pre = res;
        while (!queue1.isEmpty()) {
            ListNode next = new ListNode(queue1.poll());
            pre.next = next;
            pre = next;
        }
    
    

    gpt:

    ListNode dummy = new ListNode(-1);
    ListNode cur = dummy;
    
    while (!queue1.isEmpty()) {
        ListNode node = new ListNode(queue1.poll());
        cur.next = node;
        cur = cur.next;
    }
    
    return dummy.next;
    
    

    dummy 是一个节点,也称作虚拟节点。它是一个不存储任何实际数据的节点,只是作为辅助节点来帮助构建链表。

    在链表的头部添加节点时,如果直接添加到头节点之前,则需要对头节点进行特殊处理。而使用 dummy 节点可以避免这种特殊处理,只需要将新节点添加到 dummy 节点的 next 上即可。最后返回 dummy 节点的 next,即整个链表的头节点。

    例如,在构建一个单向链表时,可以使用 dummy 节点作为链表的头节点,它不存储任何实际数据,只是作为一个占位符。这样在添加第一个节点时,可以直接将其添加到 dummy 节点的 next 上,而不需要进行特殊处理。

    在链表的删除操作中,有时也可以使用 dummy 节点来简化代码逻辑。例如,如果需要删除链表中所有值为 x 的节点,可以使用 dummy 节点作为头节点,并将其 next 指向原链表的头节点。然后遍历整个链表,对于每个节点,如果其值为 x,则将其从链表中删除。最后返回 dummy 节点的 next,即删除 x 节点后的链表头节点。这种方法可以避免对头节点进行特殊处理。

    bing:
    以下代码可以优化的地方有:

    可以使用一个循环变量cur来代替pre,这样可以避免多余的赋值操作。
    可以在循环中直接使用queue1.poll()方法来获取队列中的元素,而不需要先定义一个next变量。
    可以在循环结束后将cur.next置为null,这样可以避免链表中出现多余的节点。
    优化后的代码如下:

        ListNode res = new ListNode(queue1.poll());
        ListNode cur = res;
    
        while (!queue1.isEmpty()) {
            cur.next = new ListNode(queue1.poll());
            cur = cur.next;
        }
        cur.next = null;
    
    

解法进化周期

1.野蛮期

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 倒序遍历两个列表
        Stack<Integer> stack1 =  new Stack();
        Stack<Integer> stack2 =  new Stack();
        Stack<Integer> stack3 =  new Stack();
        StringBuilder sb1 = new StringBuilder();
        StringBuilder sb2 = new StringBuilder();
        int ans = 0;
        while(l1.next != null){
            stack1.push(l1.val);
            l1 = l1.next;
        }

        while(l2.next != null){
            stack2.push(l2.val);
            l2 = l2.next;
        }
    
        while(stack1.size() > 0){
            sb1.append(stack1.pop());
        }

        while(stack2.size() > 0){
            sb2.append(stack2.pop());
        }

        ans = Integer.parseInt(sb1.toString()) + Integer.parseInt(sb2.toString());

        do{
            stack3.push(ans%10);
            ans = ans/10;
        }while(ans/10 != 0);

        ListNode res = new ListNode();
        ListNode cur = res;

        while(stack3.size() > 0){
            cur = add(cur, stack3.pop());
        }

        return res;

    }

    public ListNode add(ListNode node, int value ){
        node.value = value;
        ListNode node1 = new ListNode();
        node.next = node1;
        return node1;
    }
}
    
    ```

### 2.驯化期(笔试思路)

```java
class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ArrayList<Integer> l1List = new ArrayList<>();
        ArrayList<Integer> l2List = new ArrayList<>();
        while(l1 != null) {
            l1List.add(l1.val);
            l1 = l1.next;
        }
        while(l2 != null) {
            l2List.add(l2.val);
            l2 = l2.next;
        }

        // 短数组填充0
        int l1l2Difference = l1List.size() - l2List.size();

        if(l1l2Difference != 0){
            if (l1l2Difference > 0) { // l1为长链表
                for (;l1l2Difference > 0; l1l2Difference--){
                    l2List.add(0);
                }
            }else { // l1为短链表
                for (;l1l2Difference < 0; l1l2Difference++){
                    l1List.add(0);
                }
            }
        }

        // 数值从低位开始加
        int length = l1List.size();
        ArrayList<Integer> ansList = new ArrayList<>();
        int cur = 0;
        int carry = 0; //进位
        for (int i = 0; i < length; i++) {
            cur = l1List.get(i) + l2List.get(i) + carry;
            if (cur / 10 > 0){
                carry = 1;
                ansList.add(cur % 10);
            }else {
                carry = 0;
                ansList.add(cur);
            }
        }

        if (carry == 1) {
            ansList.add(1);
        }

        // 数组转换成链表
        ListNode head = new ListNode(ansList.get(0));
        ListNode curNode = head;
        for(int i = 1; i < ansList.size(); i++) {
            curNode.next = new ListNode(ansList.get(i)); // 只关注后面的node,可以避免追加额外的节点
            curNode = curNode.next;
        }

        return head;
    }
}

3.优雅期(面试思路)

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 结果链表
        ListNode dummy = new ListNode(-1);
        ListNode curNode = dummy;
        int curNum = 0;
        int carryTag = 0;
        int l1val = 0;
        int l2val = 0;
        // 对齐链表 只要有一个不为空,则进入循环 **圈重点**
        while (l1 != null || l2 != null) {
            l1val = l1 == null ? 0 : l1.val;
            l2val = l2 == null ? 0 : l2.val;
            l1 = l1 == null ? new ListNode(0) : l1;
            l2 = l2 == null ? new ListNode(0) : l2;
            curNum = l1val + l2val + carryTag;
            if (curNum / 10 > 0) {
                curNode.next = new ListNode(curNum % 10);
                curNode = curNode.next;
                carryTag = 1;
            }else {
                curNode.next = new ListNode(curNum);
                curNode = curNode.next;
                carryTag = 0;
            }
            // 循环进入下一位判断
            l1 = l1.next;
            l2 = l2.next;
        }

        if (carryTag == 1){
            curNode.next = new ListNode(1);
        }

        // **圈重点**
        return dummy.next;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

posted @ 2023-03-30 23:52  积极向上的徐先生  阅读(18)  评论(0编辑  收藏  举报