leetcode刷题详解三

2. 两数相加

思路:直接加,注意进位条件不要用if,核心代码在于sum = l1->val + l2->val + carry;

ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* dummy = new ListNode();
        ListNode* dummy_head = dummy;
        int carry = 0;
        int sum = 0;
        int single = 0;
        while(l1 && l2){
            sum = l1->val + l2->val + carry;
            carry = sum / 10;
            single = sum % 10;
            ListNode* node = new ListNode(single);
            dummy -> next = node;
            dummy = dummy->next;
            l1 = l1->next;
            l2 = l2->next;
        }
        while(l1){
            sum = l1->val + carry;
            carry = sum / 10;
            single = sum % 10;
            ListNode* node = new ListNode(single);
            dummy -> next = node;
            dummy = dummy->next;
            l1 = l1->next;
        }
        while(l2){
            sum = l2->val + carry;
            carry = sum / 10;
            single = sum % 10;
            ListNode* node = new ListNode(single);
            dummy -> next = node;
            dummy = dummy->next;
            l2 = l2->next;
        }
        if(carry){
            ListNode* node = new ListNode(carry);
            dummy -> next = node;
            dummy = dummy->next;
        }
        return dummy_head->next;
    }
445. 两数相加 II

思路:用栈,这样如果两个链表长度不相等的时候不用那么麻烦。

难点在于代码的细节控制。

  1. 当代码中出现空栈时候,则对应的数置为0,不要再写if判断了。
  2. 用第三个栈重建一个链表,这样耗费空间。可以参考第一种写法,总之这道题在于细节控制,思想上不难。
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        stack s1;
        stack s2;
        int carry = 0;
        int sum = 0;
        int single = 0;
        ListNode* dummy = new ListNode();
        ListNode* dummy_head = dummy;

        while(l1){
            s1.push(l1->val);
            l1=l1->next;
        }
        while(l2){
            s2.push(l2->val);
            l2 = l2->next;
        }
        
        while(!s1.empty() && !s2.empty()){
            sum  = s1.top() + s2.top() + carry;
            single = sum % 10;
            carry = sum / 10;
            ListNode * tmp = new ListNode(single);
            dummy -> next = tmp;
            dummy = dummy->next;
            s1.pop();
            s2.pop();
        }
        while(!s1.empty()){
            sum  = s1.top() + carry;
            single = sum % 10;
            carry = sum / 10;
            ListNode * tmp = new ListNode(single);
            dummy -> next = tmp;
            dummy = dummy->next;
            s1.pop();
        }
        while(!s2.empty()){
            sum  = s2.top() + carry;
            single = sum % 10;
            carry = sum / 10;
            ListNode * tmp = new ListNode(single);
            dummy -> next = tmp;
            dummy = dummy->next;
            s2.pop();
        }
        if(carry){
            ListNode * tmp = new ListNode(carry);
            dummy -> next = tmp;
            dummy = dummy->next;
        }

        ListNode* reverse_head = reverse(dummy_head->next);
        return reverse_head;
    }

    ListNode* reverse(ListNode* node){
        if(!node || !node->next){
            return node;
        }
        ListNode* tmp = reverse(node->next);
        node->next->next = node;
        node->next = nullptr;
        return tmp;
    }
725. 分隔链表

思路:这道题就是先求出链表长度,然后分段。

主要难点在于断链,vector每一个索引都是一个链表,在锻炼表操作这里我足足困了好长时间

其实重点就两句话:dummy = root;
root = root->next;(这个代码是设置前置节点的最好办法)

因为我们要找到前置节点,其实很简单dummy = root 中dummy就可以变成前置节点了!!!

vector splitListToParts(ListNode* root, int k) {        
    //计算长度        
    int length = 0;        
    ListNode* temp = root;        
    while(temp){            
        length++;            
        temp = temp->next;        
    }        
    //每个断链的长度        
    int arry_len = (length / k) > 0 ? (length / k) : 1;        
    int arry[k];        
    for(int i = 0;i < k; i++){            
        arry[i] = arry_len;        
    }        
    //因为长度差不超过一,因此根据length和k*arry_len的差依次给前面的每个值+1        
    int gap = 0;        
    if((k * arry_len) < length){            
        gap = length - (k * arry_len);            
        for(int i = 0;i < gap;i++){                
            arry[i]++;            
        }        
    }                
    //断链表操作        
    vector splict;        
    ListNode* dummy ;        
    for(int i = 0; i < k; i++){            
        splict.push_back(root);            
        for(int j = 0;j < arry[i];j++){                
            if(root){                    
                dummy = root;/*前置结点的精髓所在*/                    
                root = root->next;                
            }                          
        }
        if(dummy){                    
             dummy->next = NULL;                
        }  
    }        
    return splict;    
}
328. 奇偶链表

双指针然后拼接

ListNode* oddEvenList(ListNode* head) {
    if(!head || !head->next || !head->next->next){
        return head;
    }
    ListNode* odd = head;
    ListNode* even = head->next;
    ListNode* dummy = even;
    while(odd->next && even->next){
        odd->next = even->next;
        odd = odd->next;
        even->next = odd->next;
        even = even->next;
    }
    odd->next = dummy;
    return head;
}
⭕️92. 反转链表 II

反转链表精髓:

image

关于反转链表相关的递归思想,看这个

这个反转链表,思想和反转前n个链表一模一样。

只不过,第一个left不是从1开始反转,那又如何?我们可以让他变成从1开始,想一想。

反转前n个链表

leetcode刷题详解三_第1张图片
ListNode* temp = nullptr;
    ListNode* reverseN(int n,ListNode* node){
        if(n == 1){
            temp = node->next;
            return node;
        }

        ListNode* last = reverseN(n-1, node->next);
        node->next->next = node;
        node->next = temp;
        return last;
    }

这道题解,递归解法----反转链表递归解法还是比较简单的

ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode* dummy = head;
        ListNode* n1 = nullptr;
        int length = right - left +1;
        while(left > 1){
            n1 = dummy;/*记录前一个节点*/
            dummy = dummy->next;
            left--;
        }
        ListNode* n2 = reverseN(length, dummy);
    	//n1为空说明left就是1,从第一个位置反转的!!!
        if(n1){
            n1->next = n2;
        }else{
            return n2;
        }
        return head;
    }

    ListNode* temp = nullptr;
    ListNode* reverseN(int n,ListNode* node){
        if(n == 1){
            temp = node->next;
            return node;
        }

        ListNode* last = reverseN(n-1, node->next);
        node->next->next = node;
        node->next = temp;
        return last;
    }

/*******************第二种解法***********************/
/*有两个dummy节点,begin前和end后,因此要判断四次*/
ListNode* reverseBetween(ListNode* head, int left, int right) {
    if(!head || !head->next){
        return head;
    }
    ListNode* begin = head;
    ListNode* end = head;
    ListNode* dummy = nullptr;
    while(left > 1){
        dummy = begin;
        begin = begin->next;
        left--;
    }
    while(right > 1){
        end = end->next;
        right--;
    }
    ListNode* dummy2 = end->next;
    ListNode* node = reverse(begin, end);
    if(!dummy && !dummy2){
        cout<<"1"<next = dummy2;
        return end;
    }
    else if(dummy && !dummy2){
        cout<<"3"<next = end;
        return head;
    }
    cout<<"4"<next = node;
    begin->next = dummy2;
    return head;
}

ListNode* reverse(ListNode* begin, ListNode* end){
    if(begin == end){
        return begin;
    }
    ListNode* tmp = reverse(begin->next, end);
    begin->next->next = begin;
    begin->next = nullptr;
    return tmp;
}
83. 删除排序链表中的重复元素
leetcode刷题详解三_第2张图片

思路如图所示,很好理解。

ListNode* deleteDuplicates(ListNode* head) {
        if(!head || !head->next){
            return head;
        }
        int value = head->val;
        ListNode* temp = head->next;
        ListNode* carry = head;
        while(temp){
            if(temp->val == value){
                ListNode* dummy = temp;
                temp = temp->next;
                carry->next = temp;
                delete dummy;
                dummy = nullptr;
            }else{
                carry = carry->next;
                value = carry->val;
                temp = temp->next;
            }
        }
        return head;
    }

你可能感兴趣的:(leetcode,linux,算法)