707.设计链表

时间复杂度: 涉及 index 的相关操作为 O(index), 其余为 O(1)

空间复杂度: O(n)

#其他语言版

#include <iostream>
using namespace std;
int main() {
    int index = 2;
    while(--index){  // index-- 输出 1 0      --index输出 1
        cout << index << " ";
    }
}

在链表类中实现这些功能:

get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1

addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。

addAtTail(val):将值为 val 的节点追加到链表的最后一个元素

addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。

deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

代码随想录day4_出栈

这道题目设计链表的五个接口:

获取链表第index个节点的数值
在链表的最前面插入一个节点
在链表的最后面插入一个节点
在链表第index个节点前面插入一个节点
删除链表的第index个节点
#include <iostream>
#include <vector>
using namespace std;

class MyLinkedList{
public:
    struct LinkedNode{
        int val;
        LinkedNode* next;
        LinkedNode(int x):val(x),next(NULL){}
    };
    MyLinkedList(){
        _dummyHead = new LinkedNode(0);
        _size = 0;
    }
    int get(int index){
        if(index > _size - 1 ||  index < 0){
            return -1;
        }
        LinkedNode* cur = _dummyHead->next;
        while(index--){
            cur = cur->next;
        }
        return cur->val;
    }
    void addAtHead(int val){
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        _dummyHead->next = newNode;
        _size++;
    }
    void addAtTail(int val){
        LinkedNode* newNode =new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        while(cur->next != NULL){
            cur = cur->next;
        }
        cur->next = newNode;
        _size++;
    }
    void addAtIndex(int index, int val){
        if(index > _size) return;
        if(index < 0) index = 0;
        LinkedNode* newNode = new LinkedNode(val);
        LinkedNode* cur = _dummyHead;
        while(index--){
            cur = cur->next;
        }
        newNode->next = cur->next;
        cur->next = newNode;
        _size++;
    }
    void deleteAtIndex(int index){
        if (index >= _size || index < 0){
            return;
        }
        LinkedNode* cur = _dummyHead;
        while(index--){
            cur = cur->next;
        }
        LinkedNode* tmp = cur->next;
        cur->next = cur->next->next;
        delete tmp;
        tmp = NULL;
        _size--;
    }
    void printLinkedList(){
        LinkedNode* cur = _dummyHead;
        while(cur->next != NULL){
            cout << cur->next->val << " ";
            cur = cur->next;
        }
        cout << endl;
    }
private:
    int _size;
    LinkedNode* _dummyHead;
};
int main(){
    MyLinkedList* obj = new MyLinkedList();
    obj->addAtHead(1);
    obj->printLinkedList();
    obj->addAtIndex(0,2);
    obj->printLinkedList();
    obj->deleteAtIndex(0);
    obj->printLinkedList();
    return 0;

}

206.反转链表

  • 时间复杂度: O(n)
  • 空间复杂度: O(1)


题意:反转一个单链表。

示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

代码随想录day4_链表_02

首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。

//双指针法
#include <iostream>
#include <vector>
using namespace std;
struct ListNode{
    int val;
    ListNode* next;
    ListNode(int x);val(x),next(NULL)
};
class Solution{
public:
    ListNode* reverseList(ListNode* head){
        ListNode* cur = head;
        ListNode* pre = NULL;
        ListNode* tmp;
        while(cur){
            tmp = cur->next;
            cur->next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }    
};
int main(){
    vector<int> nums = {1, 2, 3, 4, 5};
    LinkNode* head = new ListNode(nums[0]);
    LinkNode* cur = head;
    for(int i = 1; i <nums.size(); i++){
        cur->next = new ListNode(nums[i]);
        cur = cur->next;
    }
    Solution s;
    ListNode* pre = s.reveserList(head);
    while(pre){
        cout << pre->val << " ";
        pre = pre->next;
    }
}




//递归法
#include <iostream>
#include <vector>
using namespace std;

struct ListNode{
    int val;
    ListNode* next;
    ListNode(int x) : val(x),next(NULL){}
};

class Solution{
public:
    ListNode* reverseList(ListNode* head) {
        // 边缘条件判断
        if(head == NULL) return NULL;
        if(head->next == NULL) return head; //最后节点指向自己

        // 递归调用,翻转第二个节点开始往后的链表
        ListNode* last = reverseList(head->next); // 倒数第二个节点
        // 翻转头节点与第二个节点的指向
        head->next->next = head;
        // 此时的head节点为尾节点,next需要指向 NULL
        head->next = NULL;
        return last;
    }
};
int main(){
    Solution s;
    //ListNode* head = new ListNode(1);
    //ListNode* node2 = new ListNode(2);
    vector<int> v = {1, 2, 3, 4};
    ListNode* head = new ListNode(v[0]);
    ListNode* p = head;
    for(int i = 1; i < v.size(); ++i){
        p->next = new ListNode(v[i]);
        p = p->next;
    }
    ListNode* res = s.reverseList(head);
    while(res){
        cout << res->val << " ";
        res = res->next;
    }
}

#容易理解的解释,网上Leetcode上面找到的 加了一点点改动,主要用于理解
    /**
     * 以链表1->2->3->4->5举例
     * @param head
     * @return
     */
#include <iostream>
#include <vector>
using namespace std;

struct ListNode{
    int val;
    ListNode* next;
    ListNode(int x) : val(x),next(NULL){}
};

class Solution{
public:
    ListNode* reverseList(ListNode* head) {
        if (head == NULL || head->next == NULL) {
            /*
                直到当前节点的下一个节点为空时返回当前节点
                由于5没有下一个节点了,所以此处返回节点5
             */
            return head;
        }
        //递归传入下一个节点,目的是为了到达最后一个节点
        ListNode* newHead = reverseList(head->next);
                /*
            第一轮出栈,head为5,head.next为空,返回5
            第二轮出栈,head为4,head.next为5,执行head.next.next=head也就是5.next=4,
                        把当前节点的子节点的子节点指向当前节点
                        此时链表为1->2->3->4<->5,由于4与5互相指向,所以此处要断开4.next=null
                        此时链表为1->2->3->4<-5
                        返回节点5
            第三轮出栈,head为3,head.next为4,执行head.next.next=head也就是4.next=3,
                        此时链表为1->2->3<->4<-5,由于3与4互相指向,所以此处要断开3.next=null
                        此时链表为1->2->3<-4<-5
                        返回节点5
            第四轮出栈,head为2,head.next为3,执行head.next.next=head也就是3.next=2,
                        此时链表为1->2<->3<-4<-5,由于2与3互相指向,所以此处要断开2.next=null
                        此时链表为1->2<-3<-4<-5
                        返回节点5
            第五轮出栈,head为1,head.next为2,执行head.next.next=head也就是2.next=1,
                        此时链表为1<->2<-3<-4<-5,由于1与2互相指向,所以此处要断开1.next=null
                        此时链表为1<-2<-3<-4<-5
                        返回节点5
            出栈完成,最终头节点5->4->3->2->1
         */
        head->next->next = head;
        head->next = NULL;
        return newHead;
    }
};
int main(){
    vector<int> v = {1,2,3,4,5};
    ListNode* head = new ListNode(v[0]);
    ListNode* p = head;
    for (int i = 1;i < v.size();++i){
        p->next = new ListNode(v[i]);
        p = p->next;
    }
    Solution s;
    ListNode* newHead = s.reverseList(head);
    while (newHead){
        cout << newHead->val << "->";
        newHead = newHead->next;
    }
}