链表中等题(下)

链表中等题(下)

LCR 028. 扁平化多级双向链表

class Solution {
public:
	// 递归
    Node *generate(Node *head) {
        if (head == nullptr) return nullptr;
        // 把后面的扁平化
        Node *next = generate(head->next);
        // 把孩子扁平化
        Node *child = generate(head->child);

        if (child != nullptr) {
            // 把child接到head和head.next之间
            head->child = nullptr;
            head->next = child;
            child->prev = head;

            if (next != nullptr) {
                Node *cur = child;
                // cur移到扁平化后的child的尾节点
                while (cur->next != nullptr) {
                    cur = cur->next;
                }
                // 把next接到child的尾节点后
                cur->next = next;
                next->prev = cur;
            }
        }
        return head;
    }


    Node *flatten(Node *head) {
        return generate(head);
    }
};
// todo 迭代

142. 环形链表 II

// todo
struct ListNode *detectCycle(struct ListNode *head) {
    // 环外节点数a 环内节点数b
    // 快慢指针经过的节点个数关系: f = 2s
    // 相遇时: f = s + n*b -> s = n*b, f = 2*n*b
    // 走到入口节点经过的节点个数k = a + n*b, 先前进a步到入口节点, 然后在环里转圈
    // f = 0, s = n*b -> f = a, s = a + n*b相遇在入口节点

    struct ListNode *slow = head, *fast = head;
    while (fast != NULL && fast->next != NULL) {
        slow = slow->next;
        fast = fast->next->next;
        // 首次相遇时,slow已经跑了b步,只需跑a步就能到达入口
        // fast返回开头head节点,也只需跑a步就能到达入口
        // 此时a是几并不知道,但是可以确定的是,slow和fast都在跑a步就会在入口相遇
        if (slow == fast) {
            fast = head;
            // 此时f = 0, s = 1*b
            while (slow != fast) {
                slow = slow->next;
                fast = fast->next;
            }
            // 结束时f = a, s = a + 1*b
            return slow;
        }
    }

    return NULL;
}

2095. 删除链表的中间节点

// 删除中偏右的节点
struct ListNode *deleteMiddle(struct ListNode *head) {
    if (head->next == NULL)return NULL;
    struct ListNode *slow = head, *fast = head, *pre = NULL;
    // 先把slow指向中偏右的节点,此时pre指向的就是slow前面的一个节点
    while (fast != NULL && fast->next != NULL) {
        pre = slow;
        slow = slow->next;
        fast = fast->next->next;
    }
    pre->next = pre->next->next;
    return head;
}

2816. 翻倍以链表形式表示的数字

// 反转链表
struct ListNode *reverse(struct ListNode *head) {
    struct ListNode *pre = NULL, *next, *cur = head;
    while (cur != NULL) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    return pre;
}

struct ListNode *doubleIt(struct ListNode *head) {
    // 进位
    int carry = 0;

    // 反转后从低位开始处理
    struct ListNode *newHead = reverse(head);
    struct ListNode *cur = newHead;
    while (cur != NULL) {
        int val = (2 * cur->val + carry) % 10;
        carry = (2 * cur->val + carry) / 10;
        cur->val = val;
        cur = cur->next;
    }

    // 多出来一个最高位
    if (carry != 0) {
        struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
        node->val = carry;
        node->next = reverse(newHead);
        return node;
    }
    return reverse(newHead);
}
// 当前位是否会由于后面一位的翻倍而导致要加上进位,取决于后面一位是否大于4
struct ListNode *doubleIt(struct ListNode *head) {
    struct ListNode *res = head;
    if (head->val > 4) {
        struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
        node->val = 1;
        node->next = head;
        res = node;
    }

    // 从原链表的开头开始
    struct ListNode *cur = head;
    while (cur != NULL) {
        cur->val = (cur->val * 2) % 10;
        // 是否要加上进位
        if (cur->next != NULL && cur->next->val > 4) cur->val++;
        cur = cur->next;
    }

    return res;
}

2058. 找出临界点之间的最小和最大距离


int *nodesBetweenCriticalPoints(struct ListNode *head, int *returnSize) {
    *returnSize = 2;
    int *res = (int *) calloc(2, sizeof(int));
    // 只有两个节点直接返回
    if (head->next->next == NULL) {
        res[0] = -1;
        res[1] = -1;
        return res;
    }

    // 前驱的值
    int preVal = head->val;
    // 当前节点
    struct ListNode *cur = head->next;
    // 第一个极值点的下标,也是最小的下标,用于计算最远距离
    int minIndex = -1;
    // 上一个极值点的下标,用于跟新最近距离
    int preIndex = -1;
    // 当前节点的下标
    int curIndex = 1;
    // 极值点之间最小距离
    int min = 0x7fffffff;

    // 从第二个节点遍历到倒数第二个节点
    while (cur->next != NULL) {
        // cur是极值点
        if ((cur->val > preVal && cur->val > cur->next->val)
            || (cur->val < preVal && cur->val < cur->next->val)) {
            if (minIndex == -1)
                minIndex = curIndex;
            else if (curIndex - preIndex < min)
                // 更新最小距离
                min = curIndex - preIndex;
            preIndex = curIndex;
        }

        preVal = cur->val;
        curIndex++;
        cur = cur->next;
    }

    // 只有一个极值点或者一个都没有
    if (preIndex == minIndex) {
        res[0] = -1;
        res[1] = -1;
    } else {
        res[0] = min;
        // 最远距离就是最后一个极值点的位置减去第一个极值点的位置
        res[1] = preIndex - minIndex;
    }
    return res;
}

92. 反转链表 II

struct ListNode *reverseBetween(struct ListNode *head, int left, int right) {
    if (head == NULL || head->next == NULL || left >= right) return head;
    // 虚拟头节点
    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode *preNode = dummyHead;
    int count = left - 1;
    // preNode为left的直接前驱
    while (count-- > 0) preNode = preNode->next;
    // 暂存反转后的子链表的尾节点
    struct ListNode *newTail = preNode->next;

    // 反转子链表
    struct ListNode *pre = NULL, *next = NULL, *cur = preNode->next;
    count = right - left + 1;
    while (count-- > 0) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    // pre是right节点,即反转后子链表的头节点,next是原链表中right的直接后继
    preNode->next = pre;
    newTail->next = next;
    return dummyHead->next;
}

面试题 16.25. LRU 缓存

// 测试用例通过了,但耗时太长。应该是慢在了lRUCacheGet时对节点的定位

struct MyListNode {
    int key;
    int val;
    struct MyListNode *prev;
    struct MyListNode *next;
};

// 带头尾节点的双向链表
typedef struct {
    struct MyListNode *dummyHead;
    struct MyListNode *dummyTail;
    int len;
    int maxLen;
} LRUCache;


LRUCache *lRUCacheCreate(int capacity) {
    LRUCache *cache = (LRUCache *) malloc(sizeof(LRUCache));
    cache->dummyHead = (struct MyListNode *) malloc(sizeof(struct MyListNode));
    cache->dummyTail = (struct MyListNode *) malloc(sizeof(struct MyListNode));
    cache->dummyHead->prev = NULL;
    cache->dummyHead->next = cache->dummyTail;
    cache->dummyTail->prev = cache->dummyHead;
    cache->dummyTail->next = NULL;
    cache->len = 0;
    cache->maxLen = capacity;
    return cache;
}

// 接到dummyHead的后面
void addToHead(struct MyListNode *dummyHead, struct MyListNode *node) {
    node->next = dummyHead->next;
    node->prev = dummyHead;
    node->next->prev = node;
    dummyHead->next = node;
}

// 把节点移到开头
void moveToHead(struct MyListNode *dummyHead, struct MyListNode *node) {
    // 把node从中间取出来
    node->prev->next = node->next;
    node->next->prev = node->prev;
    // 接到dummyHead的后面
    addToHead(dummyHead, node);
}

// 找到key对应的节点
struct MyListNode *findNode(LRUCache *obj, int key) {
    struct MyListNode *cur = obj->dummyHead->next;
    while (cur != obj->dummyTail) {
        if (cur->key == key) return cur;
        cur = cur->next;
    }
    return NULL;
}

int lRUCacheGet(LRUCache *obj, int key) {
    struct MyListNode *node = findNode(obj, key);
    if (node == NULL) return -1;
    // 刚访问过的节点要移动到开头
    moveToHead(obj->dummyHead, node);
    return node->val;
}

void lRUCachePut(LRUCache *obj, int key, int value) {
    // 如果key已存在,修改value,然后移到开头就行
    struct MyListNode *find = findNode(obj, key);
    if (find != NULL) {
        find->val = value;
        moveToHead(obj->dummyHead, find);
        return;
    }

    // 不存在,则只能插入
    if (obj->len < obj->maxLen) {
        struct MyListNode *node = (struct MyListNode *) malloc(sizeof(struct MyListNode));
        node->key = key;
        node->val = value;
        addToHead(obj->dummyHead, node);
        // 加入第一个节点时,要把虚拟尾节点的前驱指针指向当前节点
        if (obj->len == 0) obj->dummyTail->prev = node;
        obj->len++;
    } else {
        // 缓存已满,淘汰最近最久未访问的节点,也就是尾节点
        // 直接把新的值覆盖到尾节点中,再把尾节点移到开头
        struct MyListNode *tail = obj->dummyTail->prev;
        tail->key = key;
        tail->val = value;
        moveToHead(obj->dummyHead, tail);
    }
}

void lRUCacheFree(LRUCache *obj) {
    free(obj);
    obj = NULL;
}
// 用hashMap定位节点
class LRUCache {
    ListNode dummyHead;
    ListNode dummyTail;
    int capacity;
    Map<Integer, ListNode> map;

    public LRUCache(int capacity) {
        map = new HashMap<>();
        this.capacity = capacity;
        dummyHead = new ListNode();
        dummyTail = new ListNode();
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
    }

    public int get(int key) {
        if (!map.containsKey(key)) return -1;
        ListNode node = map.get(key);
        moveToHead(node);
        return node.value;
    }

    public void addToHead(ListNode node) {
        map.put(node.key, node);
        node.next = dummyHead.next;
        dummyHead.next.prev = node;
        dummyHead.next = node;
        node.prev = dummyHead;
    }

    public void moveToHead(ListNode node) {
        // 断开
        node.prev.next = node.next;
        node.next.prev = node.prev;
        // 接上
        node.next = dummyHead.next;
        dummyHead.next.prev = node;
        node.prev = dummyHead;
        dummyHead.next = node;
    }

    public void deleteNode(ListNode node) {
        map.remove(node.key);
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    public void put(int key, int value) {
        if (map.containsKey(key)) {
            ListNode node = map.get(key);
            node.value = value;
            moveToHead(node);
            return;
        }

        if (map.size() == capacity) deleteNode(dummyTail.prev);

        ListNode node = new ListNode(key, value);
        addToHead(node);
    }
}

class ListNode {
    int key;
    int value;
    ListNode prev;
    ListNode next;

    public ListNode(int key, int value, ListNode prev, ListNode next) {
        this.key = key;
        this.value = value;
        this.prev = prev;
        this.next = next;
    }

    public ListNode(int key, int value) {
        this.key = key;
        this.value = value;
    }

    public ListNode() {
    }
}
// 数组模拟循环双端队列(测试用例通过了,但耗时太长。)
struct MyNode {
    int key;
    int val;
};

typedef struct {
    struct MyNode *queue;
    int front;
    int rear;
    int size;
} LRUCache;

LRUCache *lRUCacheCreate(int capacity) {
    LRUCache *cache = (LRUCache *) malloc(sizeof(LRUCache));
    // 多留一位
    cache->size = capacity + 1;
    cache->front = 0;
    cache->rear = 0;
    cache->queue = (struct MyNode *) calloc(capacity + 1, sizeof(struct MyNode));
    return cache;
}


int getLen(LRUCache *obj) {
    return (obj->rear - obj->front + obj->size) % obj->size;
}

bool isFull(LRUCache *obj) {
    return getLen(obj) == obj->size - 1;
}

void addToHead(LRUCache *obj, int key, int value) {
    obj->front = (obj->front - 1 + obj->size) % obj->size;
    obj->queue[obj->front].key = key;
    obj->queue[obj->front].val = value;
}

void moveToHead(LRUCache *obj, int index) {
    obj->front = (obj->front - 1 + obj->size) % obj->size;
    obj->queue[obj->front].key = obj->queue[index].key;
    obj->queue[obj->front].val = obj->queue[index].val;
    while (index != obj->rear) {
        // 后一个节点往前移动一格
        obj->queue[index].key = obj->queue[(index + 1) % obj->size].key;
        obj->queue[index].val = obj->queue[(index + 1) % obj->size].val;
        index = (index + 1 + obj->size) % obj->size;
    }
    obj->rear = (obj->rear - 1 + obj->size) % obj->size;
}

int findNodeIndex(LRUCache *obj, int key) {
    int count = getLen(obj);
    int index = obj->front;
    while (count-- > 0) {
        if (obj->queue[index].key == key) return index;
        index = (index + 1 + obj->size) % obj->size;
    }
    return -1;
}

int lRUCacheGet(LRUCache *obj, int key) {
    int index = findNodeIndex(obj, key);
    if (index == -1) return -1;
    int res = obj->queue[index].val;
    moveToHead(obj, index);
    return res;
}

void lRUCachePut(LRUCache *obj, int key, int value) {
    // 若已有就修改并移到开头
    int index = findNodeIndex(obj, key);
    if (index != -1) {
        obj->queue[index].val = value;
        moveToHead(obj, index);
        return;
    }
    // 满了就要先移除末尾元素
    if (isFull(obj)) {
        obj->rear = (obj->rear - 1 + obj->size) % obj->size;
    }
    // 加到开头
    addToHead(obj, key, value);
}

void lRUCacheFree(LRUCache *obj) {
    free(obj);
    obj = NULL;
}
// 加了散列,依旧正确但超时
struct MyNode {
    int key;
    int val;
};

typedef struct {
    struct MyNode *queue;
    int front;
    int rear;
    int size;
    int *hashMap;
} LRUCache;

LRUCache *lRUCacheCreate(int capacity) {
    LRUCache *cache = (LRUCache *) malloc(sizeof(LRUCache));
    // 多留一位
    cache->size = capacity + 1;
    cache->front = 0;
    cache->rear = 0;
    cache->queue = (struct MyNode *) calloc(capacity + 1, sizeof(struct MyNode));
    // 下标对应key,值对应节点再queue中的下标
    cache->hashMap = (int *) malloc(sizeof(int) * 6000);
    for (int i = 0; i < 6000; ++i) {
        cache->hashMap[i] = -1;
    }
    return cache;
}


int getLen(LRUCache *obj) {
    return (obj->rear - obj->front + obj->size) % obj->size;
}

bool isFull(LRUCache *obj) {
    return getLen(obj) == obj->size - 1;
}

void addToHead(LRUCache *obj, int key, int value) {
    obj->front = (obj->front - 1 + obj->size) % obj->size;
    obj->queue[obj->front].key = key;
    obj->queue[obj->front].val = value;
    obj->hashMap[key] = obj->front;
}

void moveToHead(LRUCache *obj, int index) {
    obj->front = (obj->front - 1 + obj->size) % obj->size;
    obj->queue[obj->front].key = obj->queue[index].key;
    obj->queue[obj->front].val = obj->queue[index].val;
    obj->hashMap[obj->queue[obj->front].key] = obj->front;
    // 要往前搬动的元素个数
    int count = (obj->rear - index + obj->size) % obj->size - 1;
    while (count-- > 0) {
        // 后一个节点往前移动一格
        obj->queue[index].key = obj->queue[(index + 1) % obj->size].key;
        obj->queue[index].val = obj->queue[(index + 1) % obj->size].val;
        obj->hashMap[obj->queue[index].key] = index;
        index = (index + 1 + obj->size) % obj->size;
    }
    obj->rear = (obj->rear - 1 + obj->size) % obj->size;
    // 淘汰末尾元素, obj->hashMap[obj->queue[obj->rear].key] == obj->rear表示这个key不仅有效而且没有移动位置,可以直接删掉了
    // 不等时,这个元素可能是被移到前面去了,所以不用更新hashMap,否则就覆盖掉之前的移动了
    if (obj->hashMap[obj->queue[obj->rear].key] == obj->rear) obj->hashMap[obj->queue[obj->rear].key] = -1;
}

int findNodeIndex(LRUCache *obj, int key) {
    return obj->hashMap[key];
}

int lRUCacheGet(LRUCache *obj, int key) {
    int index = findNodeIndex(obj, key);
    if (index == -1) return -1;
    int res = obj->queue[index].val;
    moveToHead(obj, index);
    return res;
}

void lRUCachePut(LRUCache *obj, int key, int value) {
    // 若已有就修改并移到开头
    int index = findNodeIndex(obj, key);
    if (index != -1) {
        obj->queue[index].val = value;
        moveToHead(obj, index);
        return;
    }
    // 满了就要先移除末尾元素
    if (isFull(obj)) {
        obj->rear = (obj->rear - 1 + obj->size) % obj->size;
        if (obj->hashMap[obj->queue[obj->rear].key] == obj->rear) obj->hashMap[obj->queue[obj->rear].key] = -1;
    }
    // 加到开头
    addToHead(obj, key, value);
}

void lRUCacheFree(LRUCache *obj) {
    free(obj);
    obj = NULL;
}

LCR 021. 删除链表的倒数第 N 个结点

struct ListNode *removeNthFromEnd(struct ListNode *head, int n) {
    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode *slow = dummyHead, *fast = dummyHead;

    int count = n + 1;
    while (count-- > 0) fast = fast->next;
    while (fast != NULL) {
        slow = slow->next;
        fast = fast->next;
    }

    slow->next = slow->next->next;
    return dummyHead->next;
}

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

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;
    // pre始终指向不重复的元素的最后一个
    struct ListNode *pre = dummyHead, *cur = head;

    while (cur != NULL) {
        // 是否出现重复
        bool flag = false;
        while (cur->next != NULL && cur->next->val == cur->val) {
            flag = true;
            cur = cur->next;
        }
        if (flag) {
            // 有重复时,cur指向重复的元素的最后一个,跳过这些重复元素
            pre->next = cur->next;
            // pre指针不动,因为后面还有可能有重复的
        } else {
            // cur不是重复元素,pre可以指向cur了
            pre = cur;
        }
        cur = cur->next;
    }
    return dummyHead->next;
}
// 先遍历一遍统计元素出现次数,再次遍历删掉多次出现的元素
// 递归
struct ListNode *deleteDuplicates(struct ListNode *head) {
    if (head == NULL || head->next == NULL) return head;
    struct ListNode *cur = head;

    bool flag = false;
    while (cur->next != NULL && cur->next->val == head->val) {
        flag = true;
        cur = cur->next;
    }
    // 循环结束时,cur->next为空或者是个不同于head->val的节点

    if (flag) {
        // head到cur的节点全是相同的,都跳过
        return deleteDuplicates(cur->next);
    } else {
        head->next = deleteDuplicates(head->next);
        return head;
    }
}

1171. 从链表中删去总和值为零的连续节点

class Solution {
    public ListNode removeZeroSumSublists(ListNode head) {
        Map<Integer, ListNode> map = new HashMap<>();
        ListNode dummyHead = new ListNode();
        dummyHead.next = head;
        map.put(0, dummyHead);
        ListNode cur = head;
        int sum = 0;

        while (cur != null) {
            sum += cur.val;
            if (map.containsKey(sum)) {
                // 找到上一个值相等的节点(node的前缀和与cur的前缀和相等)
                ListNode node = map.get(sum);
                // 根据tempSum去删除map中的node(不包括)到cur(包括)的节点
                ListNode deleteNode = node.next;
                int tempSum = sum;
                while (deleteNode != cur) {
                    tempSum += deleteNode.val;
                    map.remove(tempSum);
                    deleteNode = deleteNode.next;
                }
                // 删除node(不包括)到cur(包括)的节点
                node.next = cur.next;
            } else {
                map.put(sum, cur);
            }
            cur = cur.next;
        }

        return dummyHead.next;
    }
}
// todo
class Solution {
    // 不用维护map
    public ListNode removeZeroSumSublists(ListNode head) {
        Map<Integer, ListNode> map = new HashMap<>();
        ListNode dummyHead = new ListNode(0);
        dummyHead.next = head;
        map.put(0, dummyHead);
        ListNode cur = head;
        int sum = 0;

        // 先计算前缀和(包括当前节点的值)
        while (cur != null) {
            sum += cur.val;
            map.put(sum, cur);
            cur = cur.next;
        }

        sum = 0;
        cur = dummyHead;
        // 再次计算前缀和
        while (cur != null) {
            sum += cur.val;
            // map.get(sum).next返回的要么是自己的直接后继,要么是后面和当前前缀和相等的节点
            // 如果后面有,则一定是返回后面的,因为第一次求前缀和的时候,放入map的时候后一个节点把当前节点的直接后继覆盖掉了
            // 把当前节点的next指针指向下个前缀和相等的节点的直接后继,就能跳过中间和为0的连续节点
            cur.next = map.get(sum).next;
            cur = cur.next;
        }

        return dummyHead.next;
    }
}

面试题 02.05. 链表求和

struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2) {
    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = NULL;
    struct ListNode *pre = dummyHead;

    // 进位
    int carry = 0;
    while (l1 != NULL && l2 != NULL) {
        struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
        node->val = (l1->val + l2->val + carry) % 10;
        node->next = NULL;
        carry = (l1->val + l2->val + carry) / 10;
        pre->next = node;
        pre = pre->next;
        l1 = l1->next;
        l2 = l2->next;
    }

    while (l1 != NULL) {
        int val = l1->val + carry;
        l1->val = val % 10;
        carry = val / 10;
        pre->next = l1;
        pre = pre->next;
        l1 = l1->next;
    }

    while (l2 != NULL) {
        int val = l2->val + carry;
        l2->val = val % 10;
        carry = val / 10;
        pre->next = l2;
        pre = pre->next;
        l2 = l2->next;
    }

    if (carry != 0) {
        struct ListNode *node = (struct ListNode *) malloc(sizeof(struct ListNode));
        node->val = carry;
        node->next = NULL;
        pre->next = node;
    }

    return dummyHead->next;
}

622. 设计循环队列

// 数组模拟循环队列
typedef struct {
    int *queue;
    int front;
    int rear;
    int size;
} MyCircularQueue;

MyCircularQueue *myCircularQueueCreate(int k) {
    MyCircularQueue *myCircularQueue = (MyCircularQueue *) malloc(sizeof(MyCircularQueue));
    myCircularQueue->size = k + 1;
    myCircularQueue->front = 0;
    myCircularQueue->rear = 0;
    myCircularQueue->queue = (int *) malloc(sizeof(int) * (k + 1));
    return myCircularQueue;
}

int getLen(MyCircularQueue *obj) {
    return (obj->rear - obj->front + obj->size) % obj->size;
}

bool myCircularQueueIsEmpty(MyCircularQueue *obj) {
    return obj->rear == obj->front;
}

bool myCircularQueueIsFull(MyCircularQueue *obj) {
    return getLen(obj) == obj->size - 1;
}

bool myCircularQueueEnQueue(MyCircularQueue *obj, int value) {
    if (myCircularQueueIsFull(obj)) return false;
    obj->queue[obj->rear] = value;
    obj->rear = (obj->rear + 1 + obj->size) % obj->size;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue *obj) {
    if (myCircularQueueIsEmpty(obj)) return false;
    obj->front = (obj->front + 1 + obj->size) % obj->size;
    return true;
}

int myCircularQueueFront(MyCircularQueue *obj) {
    if (myCircularQueueIsEmpty(obj)) return -1;
    return obj->queue[obj->front];
}

int myCircularQueueRear(MyCircularQueue *obj) {
    if (myCircularQueueIsEmpty(obj)) return -1;
    return obj->queue[(obj->rear - 1 + obj->size) % obj->size];
}

void myCircularQueueFree(MyCircularQueue *obj) {
    free(obj);
    obj = NULL;
}

641. 设计循环双端队列

// todo 循环单链表、循环双链表模拟
// 数组模拟循环双端队列
typedef struct {
    int *queue;
    int front;
    int rear;
    int size;
} MyCircularDeque;


MyCircularDeque *myCircularDequeCreate(int k) {
    MyCircularDeque *obj = (MyCircularDeque *) malloc(sizeof(MyCircularDeque));
    obj->size = k + 1;
    obj->front = 0;
    obj->rear = 0;
    obj->queue = (int *) malloc(sizeof(int) * (k + 1));
    return obj;
}

int getLen(MyCircularDeque *obj) {
    return (obj->rear - obj->front + obj->size) % obj->size;
}

bool myCircularDequeIsEmpty(MyCircularDeque *obj) {
    return obj->rear == obj->front;
}

bool myCircularDequeIsFull(MyCircularDeque *obj) {
    return getLen(obj) == obj->size - 1;
}

bool myCircularDequeInsertFront(MyCircularDeque *obj, int value) {
    if (myCircularDequeIsFull(obj)) return false;
    obj->front = (obj->front - 1 + obj->size) % obj->size;
    obj->queue[obj->front] = value;
    return true;
}

bool myCircularDequeInsertLast(MyCircularDeque *obj, int value) {
    if (myCircularDequeIsFull(obj)) return false;
    obj->queue[obj->rear] = value;
    obj->rear = (obj->rear + 1 + obj->size) % obj->size;
    return true;
}

bool myCircularDequeDeleteFront(MyCircularDeque *obj) {
    if (myCircularDequeIsEmpty(obj)) return false;
    obj->front = (obj->front + 1 + obj->size) % obj->size;
    return true;
}

bool myCircularDequeDeleteLast(MyCircularDeque *obj) {
    if (myCircularDequeIsEmpty(obj)) return false;
    obj->rear = (obj->rear - 1 + obj->size) % obj->size;
    return true;
}

int myCircularDequeGetFront(MyCircularDeque *obj) {
    if (myCircularDequeIsEmpty(obj)) return -1;
    return obj->queue[obj->front];
}

int myCircularDequeGetRear(MyCircularDeque *obj) {
    if (myCircularDequeIsEmpty(obj)) return -1;
    return obj->queue[(obj->rear - 1 + obj->size) % obj->size];
}

void myCircularDequeFree(MyCircularDeque *obj) {
    free(obj);
    obj = NULL;
}

2074. 反转偶数长度组的节点

// todo
struct ListNode *reverseEvenLengthGroups(struct ListNode *head) {
    struct ListNode *cur = head, *pre = NULL, *tail;
    for (int i = 1; cur != NULL; ++i) {
        int count = 0;
        // 选当前i个节点为一组,若不足则全选
        while (count < i && cur != NULL) {
            tail = cur;
            cur = cur->next;
            count++;
        }
        // 结束循环时,tail为当前组的尾节点,cur为下一组的头节点,可能为空

        if (count % 2 == 0) {
            // 该组头结点,作为下一组的前驱
            tail = pre->next;

            // temp指向当前组头节点
            struct ListNode *temp = pre->next;
            struct ListNode *next = NULL;
            // cur为下一组的头节点,接在当前组的头节点的后面,开始头插法
            pre->next = cur;
            // temp从当前组头节点,遍历到下一组的头节点,把路过的每个节点头插到pre后面
            // pre是当前组的直接前驱
            while (temp != cur) {
                // 暂存后继
                next = temp->next;
                // 头插
                temp->next = pre->next;
                pre->next = temp;
                // 遍历下一个
                temp = next;
            }
        }
        // pre为下一组的直接前驱
        pre = tail;
    }
    return head;
}
// 反转start和end之间的链表,不包括两端
void reverse(struct ListNode *start, struct ListNode *end) {
    struct ListNode *pre = NULL;
    struct ListNode *cur = start->next;
    // 反转前的头节点,反转后的尾节点
    struct ListNode *last = start->next;
    while (cur != end) {
        struct ListNode *next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    // 结束后,pre为反转后的头节点,接到start后面
    start->next = pre;
    if (last != NULL) last->next = end;
}

struct ListNode *reverseEvenLengthGroups(struct ListNode *head) {
    struct ListNode *cur = head;
    int gap = 2;

    while (cur != NULL) {
        // 当前组的直接前驱(从第二组开始)
        struct ListNode *start = cur;
        // 当前组反转前的头节点,反转后的尾节点
        struct ListNode *newEnd = cur->next;
        // 后移次数
        int count = gap;

        // 移动到下一组的直接前驱,同时也是这个组的末尾
        while (cur != NULL && count > 0) {
            cur = cur->next;
            count--;
        }

        // 处理最后一组的特殊情况
        if (cur == NULL) {
            // count多减了一次,要加上
            count++;
            // 判断最后一组的个数是否是偶数个,是偶数则也要反转
            if ((gap - count) % 2 == 0) reverse(start, NULL);
            break;
        }

        // cur != null && count == 0
        if (gap % 2 == 0) {
            reverse(start, cur->next);
            // 反转后,cur移到下一组的直接前驱
            cur = newEnd;
        }

        gap++;
    }
    return head;
}

1367. 二叉树中的链表

// 判断是否能从当前节点匹配全部链表
bool dfsJudge(struct TreeNode *root, struct ListNode *head) {
    if (head == NULL) return true;
    if (root == NULL || root->val != head->val) return false;
    return dfsJudge(root->left, head->next) || dfsJudge(root->right, head->next);
}

// 遍历二叉树
bool dfs(struct TreeNode *root, struct ListNode *head) {
    if (root == NULL) return false;
    if (dfsJudge(root, head)) return true;
    return dfs(root->left, head) || dfs(root->right, head);
}

bool isSubPath(struct ListNode *head, struct TreeNode *root) {
    return dfs(root, head);
}

61. 旋转链表

struct ListNode *reverseBetween(struct ListNode *head, int left, int right) {
    if (head == NULL || head->next == NULL || left >= right) return head;
    // 虚拟头节点
    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode *preNode = dummyHead;
    int count = left - 1;
    // preNode为left的直接前驱
    while (count-- > 0) preNode = preNode->next;
    // 暂存反转后的子链表的尾节点
    struct ListNode *newTail = preNode->next;

    // 反转子链表
    struct ListNode *pre = NULL, *next = NULL, *cur = preNode->next;
    count = right - left + 1;
    while (count-- > 0) {
        next = cur->next;
        cur->next = pre;
        pre = cur;
        cur = next;
    }
    // pre是right节点,即反转后子链表的头节点,next是原链表中right的直接后继
    preNode->next = pre;
    newTail->next = next;
    return dummyHead->next;
}

struct ListNode *rotateRight(struct ListNode *head, int k) {
    if(head == NULL || head->next == NULL) return head;
    struct ListNode *cur = head;
    int len = 0;
    while (cur != NULL) {
        len++;
        cur = cur->next;
    }
    k %= len;
    if(k == 0) return head;

    // 三次反转
    head = reverseBetween(head, 1, len);
    head = reverseBetween(head, 1, k);
    head = reverseBetween(head, k + 1, len);
    return head;
}
// 把后面的链表移到前面
struct ListNode *rotateRight(struct ListNode *head, int k) {
    if (head == NULL || head->next == NULL) return head;
    struct ListNode *cur = head;
    int len = 0;
    while (cur != NULL) {
        len++;
        cur = cur->next;
    }
    k %= len;
    if (k == 0) return head;

    struct ListNode *dummyHead = (struct ListNode *) malloc(sizeof(struct ListNode));
    dummyHead->next = head;
    struct ListNode *slow = head;
    struct ListNode *fast = head;
    while (k-- > 0) fast = fast->next;
    while (fast->next != NULL) {
        slow = slow->next;
        fast = fast->next;
    }
    // 把slow后面的链表移到链表前面
    fast->next = dummyHead->next;
    dummyHead->next = slow->next;
    // slow变成新的尾节点
    slow->next = NULL;
    return dummyHead->next;
}

355. 设计推特

// 模拟题

面试题 03.03. 堆盘子

// todo 多个子栈模拟一个栈

707. 设计链表

struct Node {
    int val;
    struct Node *pre;
    struct Node *next;
};

// 带头尾节点的双向链表
typedef struct {
    struct Node *dummyHead;
    struct Node *dummyTail;
    int len;
} MyLinkedList;

MyLinkedList *myLinkedListCreate() {
    MyLinkedList *linkedList = (MyLinkedList *) malloc(sizeof(MyLinkedList));
    linkedList->dummyHead = (struct Node *) malloc(sizeof(struct Node));
    linkedList->dummyTail = (struct Node *) malloc(sizeof(struct Node));
    linkedList->dummyHead->pre = NULL;
    linkedList->dummyHead->next = linkedList->dummyTail;
    linkedList->dummyTail->pre = linkedList->dummyHead;
    linkedList->dummyTail->next = NULL;
    linkedList->len = 0;
    return linkedList;
}

// 下标从0开始
struct Node *findNode(MyLinkedList *obj, int index) {
    if (index >= obj->len) return NULL;
    if (index < obj->len / 2) {
        // 从前往后找
        struct Node *cur = obj->dummyHead->next;
        int count = index;
        while (count-- > 0) cur = cur->next;
        return cur;
    } else {
        // 从后往前找
        struct Node *cur = obj->dummyTail;
        int count = obj->len - index;
        while (count-- > 0) cur = cur->pre;
        return cur;
    }
}

int myLinkedListGet(MyLinkedList *obj, int index) {
    struct Node *node = findNode(obj, index);
    if (node == NULL) return -1;
    return node->val;
}

void myLinkedListAddAtHead(MyLinkedList *obj, int val) {
    struct Node *node = (struct Node *) malloc(sizeof(struct Node));
    node->val = val;
    node->next = obj->dummyHead->next;
    node->pre = obj->dummyHead;
    obj->dummyHead->next = node;
    node->next->pre = node;
    obj->len++;
}

void myLinkedListAddAtTail(MyLinkedList *obj, int val) {
    struct Node *node = (struct Node *) malloc(sizeof(struct Node));
    node->val = val;
    node->pre = obj->dummyTail->pre;
    node->pre->next = node;
    node->next = obj->dummyTail;
    obj->dummyTail->pre = node;
    obj->len++;
}

void myLinkedListAddAtIndex(MyLinkedList *obj, int index, int val) {
    if (index > obj->len) return;
    if (index == obj->len) {
        myLinkedListAddAtTail(obj, val);
        return;
    }

    struct Node *node = (struct Node *) malloc(sizeof(struct Node));
    node->val = val;
    struct Node *nextNode = findNode(obj, index);
    node->next = nextNode;
    node->pre = nextNode->pre;
    nextNode->pre->next = node;
    nextNode->pre = node;
    obj->len++;
}

void myLinkedListDeleteAtIndex(MyLinkedList *obj, int index) {
    if (index >= obj->len) return;
    struct Node *deleteNode = findNode(obj, index);
    deleteNode->pre->next = deleteNode->next;
    deleteNode->next->pre = deleteNode->pre;
    free(deleteNode);
    deleteNode = NULL;
    obj->len--;
}

void myLinkedListFree(MyLinkedList *obj) {
    free(obj);
    obj = NULL;
}

LCR 029. 循环有序列表的插入

struct Node *findTail(struct Node *head) {
    struct Node *cur = head;
    int count = 0;
    // 绕一圈回到head的时候退出循环
    while (count < 2) {
        if (cur == head) count++;
        if (cur->val > cur->next->val) return cur;
        cur = cur->next;
    }
    // 循环结束了,所有cur都满足cur->val <= cur->next->val,包括lastNode <= firstNode
    // 说明所有值都一样
    return head;
}

struct Node *insert(struct Node *head, int insertVal) {
    struct Node *node = (struct Node *) malloc(sizeof(struct Node));
    node->val = insertVal;

    if (head == NULL) {
        node->next = node;
        return node;
    }

    if (head->next == head) {
        node->next = head;
        head->next = node;
        return head;
    }

    struct Node *tail = findTail(head);
    struct Node *realHead = tail->next;
    // 作为最大或最小元素插入
    if (insertVal >= tail->val || (insertVal <= realHead->val)) {
        node->next = realHead;
        tail->next = node;
        return head;
    }

    struct Node *cur = realHead;
    int count = 0;
    while (count < 2) {
        // 只跑一圈
        if (cur == realHead) count++;
        // 插入在序列中间 a <= insert <= b
        if (cur->val <= insertVal && cur->next->val >= insertVal) {
            node->next = cur->next;
            cur->next = node;
            break;
        }

        cur = cur->next;
    }
    return head;
}
posted @ 2024-01-10 00:55  n1ce2cv  阅读(11)  评论(0编辑  收藏  举报