LeetCode 初级算法 链表

 1.  删除链表中的节点

  

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。

现有一个链表 -- head = [4,5,1,9],它可以表示为:

 

 

 

 

示例 1:

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
 
A: 
这种初级题目就很简单了,将目标节点的val和next指向next的next就行
    void deleteNode(ListNode* node) {
    ListNode* next_node = node->next;
    node->val = next_node->val;
    node->next = next_node->next;
    }

 

2.  删除链表的倒数第N个节点

  

给定一个链表,删除链表的倒数第 个节点,并且返回链表的头结点。

示例:

给定一个链表: 1->2->3->4->5, 和 n = 2.

当删除了倒数第二个节点后,链表变为 1->2->3->5.

说明:

给定的 n 保证是有效的。

进阶:

你能尝试使用一趟扫描实现吗?

A:

方法1:遍历一次链表后,将所有的node存在一个list中,再删除list中指定的映射到原链表的node,可是这样会比较费时和费空间

ListNode* removeNthFromEnd(ListNode* head, int n) {
        
    vector<ListNode*> vec;
    ListNode* next = head->next;
    while (next) {
        vec.push_back(next);
        next = next->next;
    }

    next = vec[vec.size() - n];
    next->val = next->next->val;
    next->next = next->next->next;

    return head;   
    
}

方法2:更快的办法应该使用快慢指针,即两个指针每次的步长一个大一个小

在本题中,先让快指针先走N步,再让慢指针和快指针一起走

    ListNode* removeNthFromEnd(ListNode* head, int n) {
    if (head == NULL)
        return NULL;
    ListNode* fast = head;//快指针
    ListNode* slow = head;//慢指针
    //快指针提前移动n次
    for (int i = 0; i < n; i++) {
        fast = fast->next;
    }
    //删除的是链表头部
    if (fast == NULL) {
        return head->next;
    }
    //同时移动快慢指针,直到快指针到链表末尾
    //说明慢指针在要删除的位置上
    while (fast->next != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
    slow->next = slow->next->next;
    return head;
    }

 

 3.  反转链表

反转一个单链表。

示例:

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

进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

A:

就单纯个的反转链表

两种方法的效率都不错

    ListNode* reverseList(ListNode* head) {
    if (head == NULL || head->next == NULL){
        return head;
    }
    else    {
        ListNode* newNode = reverseList(head->next);
        head->next->next = head;
        head->next = NULL;
        return newNode;
    }
    }
    ListNode* reverseList(ListNode* head) {
    ListNode* ret = NULL;

    while (head)    {
        ListNode* tmp = head->next;
        head->next = ret;
        ret = head;
        head = tmp;
    }
    return ret;
    }

 

4.  合并两个有序链表

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

A:
也就是单纯的合并链表了
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
    struct ListNode* head = new ListNode(1);
    struct ListNode* now = head;
    while (l1 != NULL && l2 != NULL) {
        if (l1->val <= l2->val) {
            now->next = l1;
            l1 = l1->next;
        }
        else {
            now->next = l2;
            l2 = l2->next;
        }
        now = now->next;
    }
    if (l1 != NULL) {
        now->next = l1;
    }
    if (l2 != NULL) {
        now->next = l2;
    }
    return head->next;
}

 

5  回文链表

请判断一个链表是否为回文链表。

示例 1:

输入: 1->2
输出: false

示例 2:

输入: 1->2->2->1
输出: true

进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

A:

利用快慢指针,找到整个链表的中点,然后反转后半段,再用前半段和后半段对比

bool isPalindrome(ListNode* head) {
    if (head == NULL || head->next == NULL)
        return true;

    /*    stack<int> first_half;*/
    ListNode* one = head;
    ListNode* two = head;
    /*    first_half.push(one->val);*/
    while (one->next != NULL && two->next != NULL && two->next->next != NULL) {
        one = one->next;
        two = two->next->next;
        /*        first_half.push(one->val);*/
    }
    if (two->next != NULL) {
        one = one->next;
    }
    ListNode* ref = NULL;
    ListNode* helf = one;
    while (one != NULL) {
        ListNode* tmp = one->next;
        one->next = ref;
        ref = one;
        one = tmp;
    }
    ListNode* p = head;
    while (ref != NULL) {
        if (ref->val != p->val) {
            return false;
        }
        ref = ref->next;
        p = p->next;
    }
    return true;
}

 

方法2,利用栈先进后出的原理,再找前半段的同时将val push到stack中,再在遍历后半部分的时候将链表和stack对比

bool isPalindrome(ListNode* head) {
    if (head == NULL || head->next == NULL)
        return true;

    stack<int> first_half;
    ListNode* one = head;
    ListNode* two = head;
    first_half.push(one->val);
    while (one->next != NULL && two->next != NULL && two->next->next != NULL) {
        one = one->next;
        two = two->next->next;
        first_half.push(one->val);
    }
  //
if (two->next != NULL) { one = one->next; } while (one != NULL) { if (one->val != first_half.top()) { return false; } first_half.pop(); one = one->next; } return true; }

 

 

 

6  环形链表

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

 

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

 

 

A:

题目有点拗口,总是就是判断node是不是有环

同样是利用快慢指针,步长位1和2,只要是个环,快慢指针肯定会某一处相等

    bool hasCycle(ListNode *head) {
    ListNode* one = head;
    ListNode* two = head;

    while (two != NULL && two->next != NULL)    {
        one = one->next;
        two = two->next->next;
        if (one == two){
            return true;
        }
    }
    return false;
    }

 

 

 
posted @ 2020-04-16 22:12  GongKiro  阅读(151)  评论(0编辑  收藏  举报