zoukankan      html  css  js  c++  java
  • leetcode刷题(三)

    面试题 02.04. 分割链表

    编写程序以 x 为基准分割链表,使得所有小于 x 的节点排在大于或等于 x 的节点之前。如果链表中包含 x,x 只需出现在小于 x 的元素之后(如下所示)。分割元素 x 只需处于“右半部分”即可,其不需要被置于左右两部分之间。

    翻译:将小于x的数移到大于或者等于x的数之前

    题解

    先找到第一个大于或者等于x的节点(pos),然后遍历之后的节点,发现小于x的节点就移到(pos)之前。考察的操作:链表节点的删除插入

    实际上直接插在头节点之前也行。整道题看起是不是很像快排的(partion)操作,说明能用链表实现快排 ><

    class Solution {
    public:
        ListNode* partition(ListNode* head, int x) {
            if (!head || !head->next) return head;
    
            ListNode* root = new ListNode(-1);
            root->next = head;
    
            head = root;
            while(head->next != NULL) {
                if ((*(head->next)).val >= x) break;
                head = head->next;
            }
    
            ListNode* start = head, *pre = head;
            head = head->next; // 上面的while循环得到的是第一个大于或者等于x的节点 之前的节点
    
            while(head != NULL) {
                if ((*head).val < x) {
                    pre->next = head->next;
                    head->next = start->next;
                    start->next = head;
                
                    head = pre->next;
                }
                else {
                    pre = head;
                    head = head->next;
                }
            }
    
            return root->next;
        }
    };
    

    1367. 二叉树中的列表

    给你一棵以 root 为根的二叉树和一个 head 为第一个节点的链表。

    如果在二叉树中,存在一条一直向下的路径,且每个点的数值恰好一一对应以 head 为首的链表中每个节点的值,那么请你返回 True ,否则返回 False 。

    一直向下的路径的意思是:从树中某个节点开始,一直连续向下的路径

    题解

    思路比较明显:枚举节点,然后判断以这个节点开头是否能和给的链表匹配成功。(真的暴力)

    md,复杂度计算错了。尽管在一次匹配过程中可能要遍历(2^{len})个节点,但实际的树只有(n)个节点,所以时间复杂度(O(n*min(2^{len}, n)))。另外,我都不会写带返回值的DFS了,难受~~~

    /*
    不太喜欢这样的题,不过官方的code真的很nice,学习学习(https://leetcode-cn.com/problems/linked-list-in-binary-tree/solution/er-cha-shu-zhong-de-lie-biao-by-leetcode-solution/)
    */
    class Solution {
    public:
        bool DFS(ListNode* head, TreeNode* root) {
            if (head == NULL) return true;
            if (root == NULL) return false;
            if ((*head).val != (*root).val) return false;
            return DFS(head->next, root->left) || DFS(head->next, root->right);
        }
        bool isSubPath(ListNode* head, TreeNode* root) {
            if (head == NULL) return true;
            if (root == NULL) return false;
            return DFS(head, root) || isSubPath(head, root->left) || isSubPath(head, root->right);
        }
    };
    

    面试题35. 复杂链表的复制(好题)

    请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

    题解

    在每个节点的后面插入一个新的节点,更新random指针后,取出奇数节点,就是复制后的链表。

    想到用map实现也算是妙啊

    class Solution {
    public:
        Node* copyRandomList(Node* head) {
            if (head == NULL) return head;
    
            map<Node*, Node*> mp;     // 知道 map 和 unordered_map 的区别吗
    
            Node* start = head;
            while(start != NULL) {
                mp[start] = new Node(start->val);
                start = start->next;
            }
    
            start = head;
            while(start != NULL) {
                mp[start]->next = mp[start->next];
                mp[start]->random = mp[start->random];
                start = start->next;
            }
    
            return mp[head];
        }
    };
    

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

    给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。

    删除完毕后,请你返回最终结果链表的头节点。

    你可以返回任何满足题目要求的答案。

    题解

    常规思路是枚举区间,时间复杂度(O(n^2)).

    连续区间的和可由前缀和相减得到,所以只需要判断当前位置的前缀和是否在该位置以前出现过,出现,则说明这两个位置之间的区间和为0。因为是链表,故用map存一下拥有相同前缀和的节点。时间复杂度大概是(O(nlog_2(n)))

    加一个限制条件:最终序列的长度要最短。怎么破?

    class Solution {
    public:
        ListNode* removeZeroSumSublists(ListNode* head) {
            ListNode* root = new ListNode(-1);
            root->next = head;
    
            ListNode* h = root;
    
            map<int, ListNode*> mp;
            mp[0] = root;
    
            int sum = 0, temp_sum = 0;
            while(h->next != NULL) {
                h = h->next;
                sum += h->val;
                if (mp.find(sum) != mp.end()) {
                    ListNode* temp = mp[sum]->next;
                    mp[sum]->next = h->next;
                    
                    temp_sum = sum;
                    while(temp != h) {
                        temp_sum += temp->val;
                        mp.erase(temp_sum);      // 删除和为0的整个区间,避免干扰(红黑树的删除操作要调整节点,能不用就不用)
                        temp = temp->next;
                    }
                }
                else mp[sum] = h;
            }
    
            return root->next;
        }
    };
    

    1019. 链表中的下一个更大节点

    给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, ... 。

    每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且 node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。

    返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。

    题解

    单调栈,从后向前遍历,如果当前元素小于栈顶则压入,否则,就弹出栈顶元素。

    说哈复杂度,每个数都只入栈一次,所以(n)次循环中,总的入栈出栈次数最大可能是(2n),故复杂度(O(n))

    class Solution {
    public:
        vector<int> nextLargerNodes(ListNode* head) {
            vector<int> num;
            while(head != NULL) num.push_back(head->val), head = head->next;
    
            int n = (int)num.size();
            stack<int> st;
            st.push(0x3f3f3f3f);
    
            //vector<int> ans(n, 0);  少用一个vector,空间减少了,时间倒增加了几十ms
       
            for (int i = n - 1; i >= 0; --i) {
                while(num[i] >= st.top()) st.pop();
    
                int t = num[i];
                num[i] = st.top();
    
                st.push(t);
            }
    
            for (int &x: num) if (x == 0x3f3f3f3f) x = 0;
            return num;
        }
    };
    

    面试题 02.03. 删除中间节点

    实现一种算法,删除单向链表中间的某个节点(除了第一个和最后一个节点,不一定是中间节点),假定你只能访问该节点

    题解

    刷多了思维有点僵化,md,调换值就可以了

    /*   如果是面试,多半就over了   */
    class Solution {
    public:
        void deleteNode(ListNode* node) {
            if (node == NULL) return;
            while(node->next != NULL) {
                node->val = node->next->val;
                if (node->next->next == NULL) {
                    node->next = NULL;
                    break;
                }
                node = node->next;
            }
        }
    };
    

    实际上,将下一个节点的值赋给当前节点,然后删除下一个节点

    class Solution {
    public:
        void deleteNode(ListNode* node) {
            node->val = node->next->val;
            node->next = node->next->next;
        }
    };
    
  • 相关阅读:
    再谈TextField
    IOS-TextField知多少
    leftBarButtonItems
    LeftBarButtonItems,定制导航栏返回按钮
    Apple Mach-O Linker (id) Error "_OBJC_CLASS...错误解决办法 Apple Mach-O Linker (id) Error "_OBJC_CLASS...错误解决办法
    Unrecognized Selector Sent to Instance问题之诱敌深入关门打狗解决办法
    UNRECOGNIZED SELECTOR SENT TO INSTANCE 问题快速定位的方法
    Present ViewController,模态详解
    UILABEL AUTOLAYOUT自动换行 版本区别
    iOS自动布局解决警告Automatic Preferred Max Layout Width is not available on iOS versions prior to 8.0
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/12802972.html
Copyright © 2011-2022 走看看