leetcode题解-82. Remove Duplicates from Sorted List II && 445. Add Two Numbers II

82, 题目:

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.

For example,
Given 1->2->3->3->4->4->5, return 1->2->5.
Given 1->1->1->2->3, return 2->3.

本题是要将所有出现的重复元素全部删除,思路比较简单,就是获取重复元素的起始、终止位置,然后直接将其前面的节点指向其后面的节点就可以了。代码如下所示:

    public ListNode deleteDuplicates(ListNode head) {
        ListNode pre = new ListNode(0);
        pre.next = head;
        //使用left来记录左侧最后面的值。
        ListNode cur=head, left=pre;
        while(cur != null && cur.next != null){
            if(cur.val != cur.next.val){
                left = cur;
                cur = cur.next;
            }else{
                while(cur.next != null && cur.val == cur.next.val)
                    cur = cur.next;
                left.next = cur.next;
                cur = cur.next;
            }
        }
        return pre.next;
    }

此外还可以使用递归的方法来解决此题,思路是一样的,代码如下所示:

    public ListNode deleteDuplicates1(ListNode head) {
        if (head == null) return null;

        if (head.next != null && head.val == head.next.val) {
            while (head.next != null && head.val == head.next.val) {
                head = head.next;
            }
            return deleteDuplicates(head.next);
        } else {
            head.next = deleteDuplicates(head.next);
        }
        return head;
    }

445题,

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

这道题目是将两个数相加并返回结果,与I不同的是本题数字是反序存放的,所以我们首先要判断出二者的数字位置对应关系,此外还有一个难点就是进位如何处理。而且我们不能从链表的结尾处向前遍历,给结题带来了很大的不便。我已开始想到了递归的方法,因为递归会先计算最后的结果然后一层层反向传递回来。这样就可以解决无法从最后开始计算的问题,并且可以将仅为信息逐层传递==

    public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode res = new ListNode(0);
        ListNode list1=l1, list2=l2;
        int len1=0, len2=0;
        //计算两个链表的长度len1,len2
        while(list1 != null){
            list1 = list1.next;
            len1 ++;
        }

        while(list2 != null){
            list2 = list2.next;
            len2 ++;
        }

        list1 = l1;list2=l2;
        int flag = len1 > len2 ? dfs(list1, list2, len1-len2, res) :
                dfs(list2, list1, len2 - len1, res);
        //看最后一位是否产生进位,如果产生则在最前面加个1,否则直接返回
        if (flag == 1){
            res.val = 1;
            return res;
        }
        return res.next;

    }

    public static int dfs(ListNode l1, ListNode l2, int offset, ListNode res){
        //先将两个链表的差距抹平,offset表示链表的长度差
        if(offset > 0){
            res.next = new ListNode(0);
            res = res.next;
            //直接将链表的值加到res,如果要进位,则加1
            int sum = l1.val + dfs(l1.next, l2, offset-1, res);
            res.val = sum % 10;
            return sum / 10;
        }else{
            if(l1 == null || l2 == null)
                return 0;

            res.next = new ListNode(0);
            res = res.next;
            //将两个链表对应的值进行求和,并加上下一位置产生的进位值
            int sum = l1.val + l2.val + dfs(l1.next, l2.next, offset, res);
            res.val = sum % 10;
            return sum / 10;

        }
    }

这种方法可以击败13%的用户,然后我再discuss里面看到另外一种递归解法,可以击败85%的用户==感觉思路都是一样的,但是不知道差在哪里:

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int size1 = getLength(l1);
        int size2 = getLength(l2);
        ListNode head = new ListNode(1);
        // Make sure l1.length >= l2.length
        head.next = size1 < size2 ? helper(l2, l1, size2 - size1) : helper(l1, l2, size1 - size2);
        // Handle the first digit
        if (head.next.val > 9) {
            head.next.val = head.next.val % 10;
            return head;
        }
        return head.next;
    }
    // get length of the list
    public int getLength(ListNode l) {
        int count = 0;
        while(l != null) {
            l = l.next;
            count++;
        }
        return count;
    }
    // offset is the difference of length between l1 and l2
    public ListNode helper(ListNode l1, ListNode l2, int offset) {
        if (l1 == null) return null;
        // check whether l1 becomes the same length as l2
        ListNode result = offset == 0 ? new ListNode(l1.val + l2.val) : new ListNode(l1.val);
        ListNode post = offset == 0 ? helper(l1.next, l2.next, 0) : helper(l1.next, l2, offset - 1);
        // handle carry 
        if (post != null && post.val > 9) {
            result.val += 1;
            post.val = post.val % 10;
        }
        // combine nodes
        result.next = post;
        return result;
    }

此外,我们还可以使用一些额外的数据结构来帮助解题,但是这就失去了链表的意义,所以跟题目关系不大,代码如下所示:

public class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {

        HashMap<Integer, Integer> hm1 = new HashMap<>(); //Store the 'index' and the value of List1
        HashMap<Integer, Integer> hm2 = new HashMap<>(); //Store the 'index' and the value of List2
        int i = 1, j = 1;

        while(l1 != null){
            hm1.put(i, l1.val);
            l1 = l1.next;
            i++;
        }
        while(l2 != null){
            hm2.put(j, l2.val);
            l2 = l2.next;
            j++;
        }

        int carry = 0;
        i--; j--;
        ListNode head = null;

      //Create new nodes to the front of a new LinkedList
        while(i > 0 || j > 0 || carry > 0){

            int a = i > 0 ? hm1.get(i) : 0;
            int b = j > 0 ? hm2.get(j) : 0;
            int res = (a + b + carry) % 10;

            ListNode newNode = new ListNode(res);
            newNode.next = head;
            head = newNode;

            carry = (a + b + carry) / 10;
            i--; j--;
        }
        return head;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值