链表简单题

链表简单题

面试题 02.03. 删除中间节点

void deleteNode(struct ListNode *node) {
    // 转换成删除下一个节点
    node->val = node->next->val;
    node->next = node->next->next;
}

1290. 二进制链表转整数

int getDecimalValue(struct ListNode *head) {
    struct ListNode *cur = head;
    int res = 0;
    while (cur != NULL) {
        res <<= 1;
        res += cur->val;
        cur = cur->next;
    }
    return res;
}

面试题 02.02. 返回倒数第 k 个节点

int kthToLast(struct ListNode *head, int k) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    // 快指针先走k步
    while (k > 0) {
        fast = fast->next;
        k--;
    }
    // 快慢指针同时走
    while (fast != NULL) {
        fast = fast->next;
        slow = slow->next;
    }
    return slow->val;
}

LCR 024. 反转链表

// 迭代
struct ListNode *reverseList(struct ListNode *head) {
    struct ListNode *pre = NULL;
    struct ListNode *next;
    struct ListNode *cur = head;

    // 原地反转
    while (cur != NULL) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}
// 递归
struct ListNode *reverseList(struct ListNode *head) {
    // 递归出口
    if (head == NULL || head->next == NULL) return head;
    // 递归式
    struct ListNode *newHead = reverseList(head->next); // 递归反转后面的链表
    head->next->next = head; // 下个结点也就是反转后的尾节点,指向自己
    head->next = NULL; // 自己作为新的尾节点
    return newHead;
}

876. 链表的中间结点

// 返回向上取整的中间节点
struct ListNode *middleNode(struct ListNode *head) {
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    // 慢指针每走一步,快指针走两步
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

LCR 023. 相交链表

// 返回两个单链表相交的起始节点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int len1 = 0, len2 = 0;
    struct ListNode *p = headA, *q = headB;
    // 求长度
    while (p != NULL) {
        len1++;
        p = p->next;
    }
    while (q != NULL) {
        len2++;
        q = q->next;
    }

    // 长链表先走
    p = headA;
    q = headB;
    if (len1 > len2)
        for (int i = 0; i < len1 ### len2; ++i)
            p = p->next;
    else
        for (int i = 0; i < len2 ### len1; ++i)
            q = q->next;
    // p、q距离尾节点距离相同时,同时出发    
    while (p != NULL) {
        if (p == q)return p;
        p = p->next;
        q = q->next;
    }
    return NULL;
}

面试题 02.01. 移除重复节点

// 散列
struct ListNode *removeDuplicateNodes(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return head; // 特殊情况单独处理
    int hash[20001]; // 记录是否出现过
    memset(hash, 0, sizeof(hash));
    struct ListNode *p = head;
    hash[head->val] = 1;

    // 判断当前下个节点是否需要删除
    while (p != NULL && p->next != NULL) {
        if (hash[p->next->val] == 0) {
            // 首次出现
            hash[p->next->val] = 1;
            // 指针后移
            p = p->next;
        } else {
            // 删除已经出现过
            p->next = p->next->next;
            // 指针无需后移
        }
    }
    return head;
}
// 不使用散列
// 删除链表中所有值为k的节点
struct ListNode *removeNode(struct ListNode *head, int k) {
    struct ListNode *headNode = (struct ListNode *) malloc(sizeof(struct ListNode));
    headNode->next = head;
    struct ListNode *p = headNode;

    while (p != NULL && p->next != NULL) {
        if (p->next->val == k) {
            // 跳过节点
            p->next = p->next->next;
            // 指针无需后移
        } else {
            // 指针后移
            p = p->next;
        }
    }

    return headNode->next;
}

struct ListNode *removeDuplicateNodes(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return head; // 特殊情况单独处理
    struct ListNode *cur = head;
    while (cur != NULL && cur->next != NULL) {
        // 删除后续链表中和当前值相同的所有节点
        cur->next = removeNode(cur->next, cur->val);
        cur = cur->next;
    }
    return head;
}

21. 合并两个有序链表

// 合并升序链表(迭代)
struct ListNode *mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
    struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode));
    head->next = NULL; // 写完成,不然if (list1 != NULL)会报错
    struct ListNode *p = head;
    // 从两个链表中反复选出较小者
    while (list1 != NULL && list2 != NULL) {
        if (list1->val < list2->val) {
            p->next = list1;
            list1 = list1->next;
        } else {
            p->next = list2;
            list2 = list2->next;
        }
        p = p->next;
    }
    // 把剩余的链表直接接上
    if (list1 != NULL) p->next = list1;
    if (list2 != NULL) p->next = list2;

    return head->next;
}
// 递归
struct ListNode *mergeTwoLists(struct ListNode *list1, struct ListNode *list2) {
    // 递归出口
    if (list1 == NULL) return list2;
    if (list2 == NULL) return list1;
    // 递归体
    if (list1->val < list2->val) {
        list1->next = mergeTwoLists(list1->next, list2);
        return list1;
    } else {
        list2->next = mergeTwoLists(list1, list2->next);
        return list2;
    }
}

LCR 027. 回文链表

// 返回向上取整的中间节点
struct ListNode *findMid(struct ListNode *head) {
    struct ListNode *slow = head;
    struct ListNode *fast = head;
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;
}

// 原地反转
struct ListNode *reverseList(struct ListNode *head) {
    struct ListNode *pre = NULL;
    struct ListNode *cur = head;
    struct ListNode *next;
    while (cur != NULL) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}


bool isPalindrome(struct ListNode *head) {
    struct ListNode *mid = findMid(head);
    mid = reverseList(mid);

    struct ListNode *p = head;
    struct ListNode *q = mid;
    while (q != NULL) {
        if (p->val != q->val) return false;
        p = p->next;
        q = q->next;
    }
    return true;
}

203. 移除链表元素

// 删除链表中所有值为k的节点
struct ListNode *removeElements(struct ListNode *head, int val) {
    struct ListNode *headNode = (struct ListNode *) malloc(sizeof(struct ListNode));
    headNode->next = head;
    struct ListNode *p = headNode;

    while (p != NULL && p->next != NULL) {
        if (p->next->val == val) {
            // 跳过节点
            p->next = p->next->next;
            // 指针无需后移
        } else {
            // 指针后移
            p = p->next;
        }
    }

    return headNode->next;
}

83. 删除排序链表中的重复元素

struct ListNode *deleteDuplicates(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return head;
    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode *cur = head;
    while (cur != NULL) {
        while (cur->next != NULL && cur->val == cur->next->val) {
            // 跳过重复节点
            cur->next = cur->next->next;
        }
        cur = cur->next;
    }

    return dummyHead->next;
}

141. 环形链表

bool hasCycle(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return false;

    struct ListNode *slow = head;
    struct ListNode *fast = head->next;
    // 快慢指针,若有环,快指针迟早会追过慢指针(多跑了一个环的距离)
    while (fast != NULL && fast->next != NULL) {
        if (slow == fast)return true;
        slow = slow->next;
        fast = fast->next->next;
    }
    return false;
}
posted @ 2023-01-28 14:12  n1ce2cv  阅读(37)  评论(0编辑  收藏  举报