Leetcode C++ 链表

Leetecode 206

206. Reverse Linked List

Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL

  • 思路:
    首先设定两个指针,pre和curr,翻转指针就是将curr的next指向pre,但是由于链表是单向的,因此反转后就无法获得下一个指针,所以还需要设定第三个指针next存储curr翻转前的下一个指针。
ListNode* reverseList(ListNode* head) {
    if (!head) // head = nullptr
        return head;
    ListNode* pre = nullptr;
    ListNode* curr = head;
    while (curr) {
        ListNode* next = curr->next;
        curr->next = pre;
        // move
        pre = curr;
        curr = next;
    }
    return pre;
}

Leetecode 92

92. Reverse Linked List II

Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.
Example:
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL

  • 思路:
    使用链表轮转的方法解决链表翻转的问题。
ListNode* reverseBetween(ListNode* head, int m, int n) {
    // for m = 1
    ListNode* dummy = new ListNode();
    dummy->next = head;
    
    ListNode* prev = dummy;
    ListNode* curr = prev->next;
    ListNode* next = curr->next;
    
    // start node id = m (start from 1)
    for (int id = 1; id < m; ++id) {
        prev = prev->next;
        curr = curr->next;
        next = next->next;
    }
    
    // rotate
    for (int id = 0; id < n - m; ++id) {
        curr->next = next->next;
        next->next = prev->next;
        prev->next = next;
        next = curr->next;
    }
    return dummy->next;
}

Leetecode 86

86. Partition List

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
Example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5

  • 思路:
    使用轮换方法,将小于x的节点轮换到左边,保持顺序不变。由于使用轮换所以需要3个指针。
    start:指向最后一个大于等于x的node;
    prev:指向最后一个小于x的node;
    then:指向新发现的小于x的node;
  1. 条件1:当start值小于x时,3个指针同时前移
  2. 条件2:当start值大于等于x时,此时判断then的值,如果then的值同样大于等于x时同时后移;
  3. 条件3:如果then值小于x,那么进行轮换操作;
  4. 后处理:考虑轮换后start是否为最后节点,如果不是最后节点,那么还要考虑start下一节点的值来判断start是否需要后移;
ListNode* partition(ListNode* head, int x) {
	// 如果当前List是空或只有一个node,直接返回
    if (!head || !head->next)
        return head;
    // 构造一个虚拟节点
    ListNode* dummy = new ListNode();
    dummy->next = head;
    // 因为使用轮转方法,所以需要prev, start和the指针
    ListNode* prev = dummy;
    ListNode* start = prev->next;
    ListNode* then = start->next;
    
    while (then) {
        // 条件1(只有初始时才可能满足):start值小于x,那么所有指针向后移动
        if (start->val < x) {
            prev = prev->next;
            start = start->next;
            then = then->next;
        } else if (start->val >= x && then->val >= x) { // 条件2:此时prev不移动,start和then后移
            start = start->next;
            then = then->next;
        } else if (start->val >= x && then->val < x) { // 条件3:此时进行轮换操作
            // 轮换操作
            start->next = then->next;
            then->next = prev->next;
            prev->next = then;
            // 操作后处理,要考虑轮换后start是否为最后节点
            prev = prev->next;
            if (start->next) { // 轮换后如果start的next节点存在
                if (start->next->val >= x) // 如果start的next存在,根据值大小判断start是否后移
                    start = start->next;
                then = start->next;
            } else // start是最后一个节点
                then = nullptr;
        }
    }
    ListNode* res = dummy->next;
    delete dummy;
    return res;
}

Leetecode 328

328. Odd Even Linked List

Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes.
You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.
Example 1:
Input: 1->2->3->4->5->NULL
Output: 1->3->5->2->4->NULL

  • 思路:
    使用两个指针交替指向对方的next然后再前进一步的方法,因为连接后even链表再尾部,因此终止条件设置为even本身或其next为nullptr时终止。由于要连接两个链表,所以要首先保存被连接的链表的第一个元素的指针。
ListNode* oddEvenList(ListNode* head) {
    if (!head || !head->next)
        return head;
    ListNode* odd = head;
    ListNode* even = head->next;
    ListNode* temp = even; // for link odd and even finally
    
    while (even && even->next) {
        odd->next = even->next;
        odd = odd->next;
        even->next = odd->next;
        even = even->next;
    }
    odd->next = temp;
    return head;
    
}

Leetecode 2

2. Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Example 1:
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.

  • 思路:
  1. 使用dummy head指向存储结果的新List的头指针,可以统一循环中指针向后移动的语句;
  2. 在while开始处new ListNode,保证新List长度和l1或l2相同,便于后期处理;
  3. 注意循环结束后如果flag位是1,那么需要添加新的节点,存储flag位;
  4. 补上nullptr;
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    ListNode* res = new ListNode();
    ListNode* start = res;
    int flag = 0;
    int new_val = 0;
    while (l1 || l2) {
        start->next = new ListNode();
        start = start->next;
        int l1_val = l1 ? l1->val : 0;
        int l2_val = l2 ? l2->val : 0;
        
        int sum = l1_val + l2_val + flag;
        new_val = sum % 10;
        flag = sum / 10;
        start->val = new_val;
        
        if (l1)
            l1 = l1->next;
        if (l2)
            l2 = l2->next;  
    }
    if (flag) {
        start->next = new ListNode();
        start = start->next;
        start->val = flag;
    }
    start->next = nullptr;
    return res->next;
}

Leetecode 445

445. Add Two Numbers II

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

  • 思路:
  1. 将list压入栈中,实现元素反转;
  2. 弹出栈然后相加,注意增加flag存储溢出(类似Leetcode 2);
  3. 如果存储结果到List中,那么需要反转结果List;如果存储结果到stack中,那么通过结果stack再直接构造List即可。
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
    // push into stack
    stack<int> s1, s2, res;
    while (l1) {
        s1.push(l1->val);
        l1 = l1->next;
    }
    while (l2) {
        s2.push(l2->val);
        l2 = l2->next;
    }
    
    /*
    ListNode* dummy = new ListNode();
    ListNode* curr = dummy;
    */
    // add
    int flag = 0;
    int sum = 0;
    while (!s1.empty() || !s2.empty()) {
        //curr->next = new ListNode();
        //curr = curr->next;
        
        int s1_val = s1.empty() ? 0 : s1.top();
        int s2_val = s2.empty() ? 0 : s2.top();
        
        int temp = s1_val + s2_val + flag;
        sum = temp % 10;
        flag = temp / 10;
        //curr->val = sum;
        res.push(sum);
        
        if (!s1.empty())
            s1.pop();
        if (!s2.empty())
            s2.pop();
    }
    if (flag) {
        /*
        curr->next = new ListNode();
        curr = curr->next;
        curr->val = flag;
        */
        res.push(flag);
    }
    //curr->next = nullptr;
    
    /*
    // reverse result
    curr = dummy->next;
    ListNode* next = curr->next;
    while (next) {
        curr->next = next->next;
        next->next = dummy->next;
        dummy->next = next;
        
        next = curr->next;
    }
    return dummy->next;
    */
    // create result list by res stack
    ListNode* res_dummy = new ListNode();
    ListNode* res_curr = res_dummy;
    while (!res.empty()) {
        res_curr->next = new ListNode();
        res_curr = res_curr->next;
        res_curr->val = res.top();
        res.pop();
    }
    res_curr->next = nullptr;
    return res_dummy->next;
}

Leetecode 82

82. Remove Duplicates from Sorted List II

Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
Return the linked list sorted as well.
Example 1:
Input: 1->2->3->3->4->4->5
Output: 1->2->5
Example 2:
Input: 1->1->1->2->3
Output: 2->3

  • 思路1:
    因为设计节点的删除,所以首先构造虚拟头指针,并分别设置prev、curr和next指针。
    分所有情况讨论,条件分别为:curr与next是否相邻、next是否为空、curr值与next值是否相等。
    因为值相等需要next不能为空,因此将curr与next是否相邻作为最外层条件。
ListNode* deleteDuplicates(ListNode* head) {
    if (!head || !head->next) 
        return head;
    ListNode* dummy = new ListNode();
    dummy->next = head;
    ListNode* prev = dummy;
    ListNode* curr = prev->next;
    ListNode* next = curr->next;
    
    /*
    1. curr and next are adjcent && next is null;
    2. curr and next are adjcent && next is not null && curr->val = next->val;
    3. curr and next are adjcent && next is not null && curr->val != next->val;
    4. curr and next are NOT adjcent && next is null;
    5. curr and next are NOT adjcent && next is not null && curr->val = next->val;
    6. curr and next are NOT adjcent && next is not null && curr->val != next->val;
    */
    while (curr) {
        if (curr->next == next) {// curr and next are adjcent
            if (!next) { // next is nullptr (1)
                curr = curr->next; // curr is nullptr now
            } else { // next is NOT nullptr
                if (curr->val == next->val) { // curr->val = next->val (2)
                    next = next->next;
                } else { // curr->val != next->val (3)
                    prev = prev->next;
                    curr = curr->next;
                    next = next->next;
                }
            }
        } else { // curr and next are NOT adjcent
            if (!next) { // next is nullptr (4)
                prev->next = next;
                ListNode* del = curr;
                while (del != next) {
                    curr = curr->next;
                    delete del;
                    del = curr;
                }
            } else { // next is NOT nullptr
                if (curr->val == next->val) { // curr->val = next->val (5)
                    next = next->next;
                } else { // curr->val != next->val (6)
                    prev->next = next;
                    ListNode* del = curr;
                    while (del != next) {
                        curr = curr->next;
                        delete del;
                        del = curr;
                    }
                    next = next->next;
                }
            }
            
        }                  
    }
    return dummy->next;
}

*思路2:
这个思路比较简单,首先建立一个ListNode虚拟节点,然后通过判断head与head->next是否相同,相同则head向后移动,不同则使用虚拟节点将head串起来。
实现可参考连接.

Leetecode 24

24. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.
You may not modify the values in the list’s nodes. Only nodes itself may be changed.
Example1:
Input: head = [1,2,3,4]
Output: [2,1,4,3]
Example 2:
Input: head = []
Output: []
Example 3:
Input: head = [1]
Output: [1]

  • 思路:
  1. 交换List中两节点(curr和next);
  2. 交换后prev和curr节点指针向后移动两位;
  3. 判断终止条件,就是要保证带交换的两个节点(curr和next)都不能为null;
ListNode* swapPairs(ListNode* head) {
    if (!head || !head->next) 
        return head;
    ListNode* dummy = new ListNode();
    dummy->next = head;
    ListNode* prev = dummy;
    ListNode* curr = dummy->next;
    ListNode* next = curr->next;
    
    while (true) {
        // exchange
        prev->next = next;
        curr->next = next->next;
        next->next = curr;
        
        prev = curr;
        curr = prev->next;
        // terminal condition
        if (!curr)
            break;
        if (!curr->next)
            break;
        next = curr->next;
    }
    return dummy->next;
}

Leetecode 25

25. Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes, in the end, should remain as it is.
Follow up:
Could you solve the problem in O(1) extra memory space?
You may not alter the values in the list’s nodes, only nodes itself may be changed.
Example 1:
Input: head = [1,2,3,4,5], k = 2
Output: [2,1,4,3,5]
Example 2:
Input: head = [1,2,3,4,5], k = 3
Output: [3,2,1,4,5]
Example 3:
Input: head = [1,2,3,4,5], k = 1
Output: [1,2,3,4,5]
Example 4:
Input: head = [1], k = 1
Output: [1]

  • 思路:
    总体还是通过链表的轮转方法,注意进行反转的前提条件。
  1. 首先检测是否满足反转的前提条件,待反转的节点不为空(也是反转结束的条件),通过设置一个check指针来判断;
  2. 使用连边的轮转方法,轮转k-1次,也就实现了k个节点的反转;
  3. 将prev指针向前移动至start,然后循环进行判断和k-1次轮转;
ListNode* reverseKGroup(ListNode* head, int k) {
    if (!head || !head->next || k==1)
        return head;
    ListNode* dummy = new ListNode();
    dummy->next = head;
    ListNode* prev = dummy;
    ListNode* start = nullptr;
    ListNode* next = nullptr;
    ListNode* check = nullptr;
    
    while (true) {
        // check for reverse
        check = prev;
        for (int i = 0; i < k; ++i) {
            if (!check->next)
                return dummy->next;
            check = check->next;
        }
        
        start = prev->next;
        next = start->next;
        // reverse
        for (int i = 0; i < (k - 1); ++i) {
            start->next = next->next;
            next->next = prev->next;
            prev->next = next;
            // next rotate
            next = start->next;
        }
        // next group
        prev = start;
    }
    return dummy->next;
}

Leetecode 147

147. Insertion Sort List

Sort a linked list using insertion sort.
Algorithm of Insertion Sort:
(1) Insertion sort iterates, consuming one input element each repetition, and growing a sorted output list.
(2) At each iteration, insertion sort removes one element from the input data, finds the location it belongs within the sorted list, and inserts it there.
(3) It repeats until no input elements remain.

  • 思路:
  1. 定义一个新列表,并使用一个虚拟节点dummy指向该列表,初始为nullptr;
  2. 使用insert指针指向head列表中待插入的节点,并将该节点从head列表中取出成独立节点;
  3. 使用start指针从dummy开始向后遍历结果列表,比较start->next和insert,当发现比insert节点值大时,将insert节点插入到start和start->next节点之间;
  4. 当遍历结束时,如果插入条件始终不满足,那么将insert节点作为结果列表最后一个节点进行插入;
ListNode* insertionSortList(ListNode* head) {
    if (!head || !head->next)
        return head;
    ListNode* dummy = new ListNode(INT_MIN);
    dummy->next = nullptr;
    ListNode* start = dummy;   
    ListNode* insert = head;
    
    while (insert) {
        // 从dummy重新遍历结果列表
        start = dummy;
        // 将insert节点从head列表中取出,作为一个单独节点
        head = head->next;
        insert->next = nullptr;
        while (start->next) {
            if (start->next->val > insert->val) { // 插入条件3
                insert->next = start->next;
                start->next = insert;
                break;
            } else {
                start = start->next;
            }
        }
        if (!start->next) { // 插入条件4
            insert->next = start->next;
            start->next = insert;
        }
        res;
    }
    return dummy->next;  
}

Leetecode 148

148. Sort List

Given the head of a linked list, return the list after sorting it in ascending order.
Follow up: Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?

  • 思路:
    使用链表的归并排序算法,额外使用一个节点。
  1. 将一个列表分割为两个,使用快慢指针方法;
  2. 实现将两个列表从小到大排序,merge为一个列表;
  3. 递归使用
// 排序归并
ListNode* mergeList(ListNode* l1, ListNode* l2) {
    ListNode* l = new ListNode();
    ListNode* start = l;
    while (l1 && l2) {
        if (l1->val < l2->val) {
            start->next = l1;
            l1 = l1->next;
        } else {
            start->next = l2;
            l2 = l2->next;
        }
        start = start->next;
    }
    if (l1)
        start->next = l1;
    if (l2)
        start->next = l2;
    ListNode* res = l->next;
    delete l;
    return res;
}
// 分割列表为两部分
ListNode* sortList(ListNode* head) {
    if (!head || !head->next)
        return head;
    // 使用快慢指针来获取列表中间位置节点
    ListNode* fast = head;
    ListNode* slow = head;
    // find mid list
    while (fast->next && fast->next->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    ListNode* right = slow->next;
    slow->next = nullptr;// 将列表分为两个列表
    // 递归
    ListNode* l1 = sortList(head);
    ListNode* l2 = sortList(right);
    return mergeList(l1, l2);
}

Leetecode 237

237. Delete Node in a Linked List

Write a function to delete a node in a singly-linked list. You will not be given access to the head of the list, instead you will be given access to the node to be deleted directly.
It is guaranteed that the node to be deleted is not a tail node in the list.
Example 1:
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function.

  • 思路:
    直接删除指定的链表中的节点,方法时将下一个节点复制到待删除的节点,然后删除下一个节点。
    注意:该删除方法无法删除链表的最后一个节点!!
void deleteNode(ListNode* node) {
    if (!node)
        return;
    if (!node->next) {
        delete node;
        node = nullptr;
    }
    ListNode* del = node->next;
    node->val = del->val;
    node->next = del->next;
    delete del;
}

Leetecode 19

19. Remove Nth Node From End of List

Given the head of a linked list, remove the nth node from the end of the list and return its head.
Follow up: Could you do this in one pass?
Example 1:
Input: head = [1,2,3,4,5], n = 2
Output: [1,2,3,5]

  • 思路:
  1. 首先构造出两个节点start和end,二者之间的间距n个节点;
  2. 同时移动两个节点,直到end指向列表末尾,此时start指向倒数第n个节点;
  3. 删除start节点即可。
ListNode* removeNthFromEnd(ListNode* head, int n) {
    ListNode* dummy = new ListNode();
    dummy->next = head;
    ListNode* prev = dummy;
    ListNode* start = head;
    ListNode* end = start;
    // 拉开start和end之间的距离满足n个节点
    for (int i = 0; i < n - 1; ++i) {
        if (!end->next)
            throw runtime_error("length of list less than n!\n");
        end = end->next;
    }
    // start和end同时向后移动,直到end达到列表末尾
    while (end->next) {
        prev = prev->next;
        start = start->next;
        end = end->next;
    }
    // 输出start节点(倒数第n个节点)
    prev->next = start->next;
    delete start; 
     
    return dummy->next;;
}

Leetecode 61

61. Rotate List

Given the head of a linked list, rotate the list to the right by k places.
Example 1:
Input: head = [1,2,3,4,5], k = 2
Output: [4,5,1,2,3]
Example 2:
Input: head = [0,1,2], k = 4
Output: [2,0,1]

  • 思路:
  1. 获得链表的长度count,并获取一个指向最后一个节点的指针start
  2. 计算实际转动的次数: k = count - k % count
  3. 将链表转换为一个环(start->next = head)
  4. 通过start指针向前移动k次,得到prev指针
  5. 返回prev->next作为头指针
ListNode* rotateRight(ListNode* head, int k) {
    if (!head || !head->next)
        return head;
    
    int count = 1;
    ListNode* start = head;
    while(start->next) {
        start = start->next;
        count++;
    }
    // make a circle
    start->next = head;
    // move prev pointer
    k = count - (k % count);
    ListNode* prev = start;
    for (int i = 0; i < k; ++i) {
        prev = prev->next;
    }
    ListNode* ret = prev->next;
    prev->next = nullptr;
    
    return ret;
}

Leetecode 143

143. Reorder List

Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You may not modify the values in the list’s nodes, only nodes itself may be changed.
Example 1:
Given 1->2->3->4, reorder it to 1->4->2->3.
Example 2:
Given 1->2->3->4->5, reorder it to 1->5->2->4->3.

  • 思路
  1. 寻找中间节点(快慢指针),将列表分割为两个列表
  2. 反转第二个列表
  3. 将两个列表进行merge操作
void reorderList(ListNode* head) {
   if (!head || !head->next)
       return;
   // find mid node and split into two lists
   ListNode* prev = new ListNode();
   prev->next = head;
   ListNode* mid = head;
   ListNode* end = head;
   while (true) {
       // odd number
       if (!end->next) {
           break;
       }
       // even number
       if (!end->next->next) {
           prev = prev->next;
           mid = mid->next;
           break;
       }
       // move to next
       prev = prev->next;
       mid = mid->next;
       end = end->next->next;
   }
   prev->next = nullptr; // split into two lists
   
   // reverse mid list
   ListNode* dummy = new ListNode();
   dummy->next = mid;
   ListNode* next = mid->next;
   while (next) {
       mid->next = next->next;
       next->next = dummy->next;
       dummy->next = next;
       
       next = mid->next;
   }
   mid = dummy->next;
   // merge
   ListNode* start = head;
   while (start && mid) {
       dummy->next = start;
       start = start->next;
       
       dummy->next->next = mid;
       mid = mid->next;
       
       dummy = dummy->next->next;
   }
   if (start)
       dummy->next = start;
   if (mid)
       dummy->next = mid;
}

Leetecode 234

234. Palindrome Linked List

Given a singly linked list, determine if it is a palindrome.
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true

  • 思路:
  1. 找到中间节点(快慢指针)
  2. 反转第二个List
  3. 逐一对比两个List的元素是否相同
bool isPalindrome(ListNode* head) {
    if (!head || !head->next)
        return true;
    // find mid node
    ListNode* fast = head;
    ListNode* low = head;
    while (true) {
        if (!fast->next)
            break;
        if (!fast->next->next)
            break;
        low = low->next;
        fast = fast->next->next;
    }
    ListNode* mid = low->next;
    // reverse
    ListNode* dummy = new ListNode();
    dummy->next = mid;
    ListNode* next = mid->next;
    while (next) {
        mid->next = next->next;
        next->next = dummy->next;
        dummy->next = next;
        
        next = mid->next;
    }
    // compare
    mid = dummy->next;
    while (mid) {
        if (mid->val != head->val)
            return false;
        mid = mid->next;
        head = head->next;
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值