链表

  ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int len1=1;//记录l1的长度
        int len2=1;//记录l2的长度
        ListNode* p=l1;
        ListNode* q=l2;
        while(p->next!=NULL)//获取l1的长度
        {
            len1++;
            p=p->next;
        }
        while(q->next!=NULL)//获取l2的长度
        {
            len2++;
            q=q->next;
        }
        if(len1>len2)//l1较长,在l2末尾补零
        {
            for(int i=1;i<=len1-len2;i++)
            {
                q->next=new ListNode(0);
                q=q->next;
            }
        }
        else//l2较长,在l1末尾补零
        {
            for(int i=1;i<=len2-len1;i++)
            {
                p->next=new ListNode(0);
                p=p->next;
            }
        }
        p=l1;
        q=l2;
        bool count=false;//记录进位
        ListNode* l3=new ListNode(-1);//存放结果的链表
        ListNode* w=l3;//l3的移动指针
        int i=0;//记录相加结果
        while(p!=NULL&&q!=NULL)
        {
            i=count+p->val+q->val;
            w->next=new ListNode(i%10);
            count=i>=10?true:false;
            w=w->next;
            p=p->next;
            q=q->next;
        }
        if(count)//若最后还有进位
        {
            w->next=new ListNode(1);
            w=w->next;
        }
        return l3->next; 
    }
};

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:

输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int a=0,c=0,b=0;
        ListNode* p=l1;
        ListNode* q=l2;
        ListNode* ne=new ListNode(0,nullptr);
        ListNode* w=ne;
        while(p!=NULL&&q!=NULL)
        {
            c=(p->val+q->val)+b;
            w->next=new ListNode(c%10);
            b=c/10;
            w=w->next;
            p=p->next;
            q=q->next;
        }
        while(p==NULL&&q!=NULL)
        {
            c=q->val+b;
            w->next=new ListNode(c%10);
            b=c/10;
            w=w->next;
            q=q->next;
        }
        while(q==NULL&&p!=NULL)
        {
            c=p->val+b;
            w->next=new ListNode(c%10);
            b=c/10;
            w=w->next;
            p=p->next;
        }
        if(b)
        {w->next=new ListNode(1);
         w=w->next;}
        return ne->next;

    }
}

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
         ListNode* big = new ListNode(-1);
         ListNode* let = new ListNode(-1);
         ListNode *ret = let,*da = big;
         while(head != NULL){
             if(head->val < x){
                 let->next = head;
                 let = let->next;
             }else{
                 big->next = head;
                 big = big->next;
             }
             head = head->next;
         }
         big->next = NULL;
         let->next = da->next;
         return ret->next;
    }
};

 

解题步骤
建立快指针p和慢指针q,记n的初始值为in
快指针p先走,同时变量n自减
当n自减到0时,p已经比慢指针q先走了in步,此后两个指针开始同步移动
当p指向NULL时,遍历结束,循环体不再执行,故此时p刚好比q多走了in+1步,直接删除q的后一结点即可
特殊情况分析:需要删除头节点时,p最多只会比q多走n步,q并未移动,这与删除倒数第n-1个结点的情况是一样的,不过这种情况下n只会自减到0,直接返回头结点的下一个结点即可

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode *p = head, *q = head;
    while(p){
        if(n < 0){ q = q -> next; }       
        n--;
        p = p -> next;
    }
    if(n == 0){ return head -> next; }
    q -> next = q -> next -> next;
    return head;
}

 

方法一:迭代
假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3。

在遍历列表时,将当前节点的 next 指针改为指向前一个元素。由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!

Java

public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}

 


复杂度分析

时间复杂度:O(n),假设 nn 是列表的长度,时间复杂度是 O(n)。
空间复杂度:O(1)。
方法二:递归
递归版本稍微复杂一些,其关键在于反向工作。假设列表的其余部分已经被反转,现在我该如何反转它前面的部分?

 

 

public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next);
head.next.next = head;
head.next = null;
return p;
}

复杂度分析

时间复杂度:O(n),假设 nn 是列表的长度,那么时间复杂度为 O(n)。
空间复杂度:O(n),由于使用递归,将会使用隐式栈空间。递归深度可能会达到 nn 层。

 

posted @ 2020-05-02 21:23  刘通1997  阅读(172)  评论(0编辑  收藏  举报