算法综合设计实验题解

递归

21 合并两个有序链表

正常可使用双指针法遍历,但还可以用递归实现。

class Solution {
    
    
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
    
    
        if (!list1) return list2;
        else if (!list2) return list1;
        else if (list1->val < list2->val) {
    
    
            list1->next = mergeTwoLists(list1->next, list2);
            return list1;
        } else {
    
    
            list2->next = mergeTwoLists(list1, list2->next);
            return list2;
        }
    }
};

60 排序序列

试画出递归树,发现第 m m m 层分支下有 ( n − m ) ! (n-m)! (nm)! 个情况。于是可以依次考察 k k k ( n − 1 ) ! (n-1)! (n1)! 1 ! 1! 1! 的商 q q q,其为剩余数字按顺序的第 q q q 个。分析边界问题:确定倒数第2位时,也确定了最后一位,即 1 ! = 1 1!=1 1!=1 同时序数从 0 0 0 开始。
此即逆康托展开。

class Solution {
    
    
    const vector<int> factorial = {
    
    1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
public:
    string getPermutation(int n, int k) {
    
    
        string order;
        string seq = string("123456789").substr(0, n);
        --k;
        while(k) {
    
    
            unsigned int quotient = k / factorial[n - 1];
            order.push_back(seq[quotient]);
            seq.erase(seq.begin() + quotient);
            k %= factorial[n - 1];
            --n;
        }
        return order + seq;
    }
};

143 重排链表

经典链表算法的结合:①快慢指针法找到链表中间结点;②对中间节点以后的部分进行三指针迭代翻转;③交错合并两个链表。
(注:分割链表时前链表尾指针需维护或指向空)

class Solution {
    
    
public:
    void reorderList(ListNode* head) {
    
    
        if (!head) return;
        ListNode* list1 = head;
        ListNode* mid = midNode(head);
        ListNode* list2 = mid->next;
        mid->next = nullptr;
        list2 = reverseList(list2);
        mergeList(list1, list2);
    }

    ListNode* midNode(ListNode* head) {
    
    
        ListNode* slow = head;
        ListNode* fast = head;
        while(fast->next && fast->next->next) {
    
    
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    ListNode* reverseList(ListNode* head) {
    
    
        ListNode* prev = nullptr;
        ListNode* curr = head;
        ListNode* next = nullptr;
        while (curr) {
    
    
            next = curr->next;
            curr->next = prev;
            prev = curr;
            curr = next;
        }
        return prev;
    }

    void mergeList(ListNode* list1, ListNode* list2) {
    
    
        ListNode* curr1 = nullptr;
        ListNode* curr2 = nullptr;
        while (list1 && list2) {
    
    
            curr1 = list1->next;
            curr2 = list2->next;
            list1->next = list2;
            list1 = curr1;
            list2->next = list1;
            list2 = curr2;
        }
    }
};

233 数字 1 的个数

数学题,关键在于正确写出计数表达式:
⌊ n 1 0 i + 1 ⌋ 1 0 i + min ⁡ { max ⁡ { n ( m o d   1 0 i + 1 ) − 1 0 i + 1 , 0 } , 1 0 i } . \lfloor \frac{n}{10^{i+1}}\rfloor10^i+\min\{\max\{n({\rm mod}\ 10^{i+1})-10^i+1,0\},10^i\}. 10i+1n10i+min{ max{ n(mod 10i+1)10i+1,0},10i}.

class Solution {
    
    
    const vector<long long> mag = {
    
    1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000};
public:
    int countDigitOne(int n) {
    
    
        int cnt = 0;
        for (int i = 0; n >= mag[i]; ++i)
            cnt += (n / mag[i + 1]) * mag[i] + min(max(n % mag[i + 1] - mag[i] + 1, 0LL), mag[i]);
        return cnt;
    }
};

342 4 的幂

掩码 (mask) 题: 2 2 2 的幂二进制中至多有 1 1 1 位为 0 0 0;在此基础上 4 4 4 的幂二进制中 1 1 1 只能出现在低位开始的偶数位上。

class Solution {
    
    
public:
    bool isPowerOfFour(int n) {
    
    
        return n > 0 && !(n & (n-1)) && !(n & 0xAAAAAAAA);
    }
};

贪心

55 跳跃游戏

不难发现导致无法抵达终点的只有出现数字 0 0 0 的情况,反向遍历并记录所需跨度,最终跨度大于 1 1 1 等效于起点数字为 0 0 0

class Solution {
    
    
public:
    bool canJump(vector<int>& nums) {
    
    
        int span = 1;
        for (int i = nums.size() - 1; i > 0; i--) {
    
    
            if (nums[i - 1] >= span) span = 0;
            span++;
        }
        return span == 1;
    }
};

134 加油站

正向遍历,若 x x x 无法抵达 y + 1 y+1 y+1,那么 x x x y y y 间的任何一点也都不可能抵达 y + 1 y+1 y+1,从而剪支。
但还可以采用反向遍历,转而考虑额外油量需求:不存在解时需求为正;存在解时出发点一定为使得需求最小的点。

class Solution {
    
    
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
    
    
        int remains = 0, maxRemains = 0, start = 0;
        for (int i = gas.size() - 1; i >= 0; i--) {
    
    
            remains += gas[i] - cost[i];
            if (remains >= maxRemains) {
    
    
                maxRemains = remains;
                start = i;
            }
        }
        return remains < 0 ? -1 : start;
    }
};

135 分发糖果

可以转而考察递增递减序列:递增序列中下一位比上一位多 1 1 1,递减序列中每多一位则前面所有位均多 1 1 1 (即增加序列长度值)。
边界情况:不增不减时,序列结束;递减序列长超过前面递增序列长时,递增序列的末位视为递减序列的初位。

class Solution {
    
    
public:
    int candy(vector<int>& ratings) {
    
    
        int cnt = 1, incLen = 1, decLen = 0, incPrev = 1;
        for (int i = 1; i < ratings.size(); i++) {
    
    
            if (ratings[i] >= ratings[i - 1]) {
    
    
                prev = ratings[i] == ratings[i - 1] ? 1 : incPrev + 1;
                cnt += incPrev; incLen = incPrev; decLen = 0;
            } else {
    
    
                decLen = decLen + 1 == incLen ? decLen + 2 : decLen + 1;
                cnt += decLen; prev = 1;
            }
        }
        return cnt;
    }
};

605 种花问题

当前位置和前后位置都为 0 0 0 时待种花数 − 1 -1 1,待种花为 0 0 0 时可直接返回以剪支。

class Solution {
    
    
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
    
    
        if (!n) return true;
        for (int i = 0; i < flowerbed.size(); i++) {
    
    
            if ((i == 0 || flowerbed[i - 1] == 0) && flowerbed[i] == 0 &&
            (i == flowerbed.size() - 1 || flowerbed[i + 1] == 0)) {
    
    
                n--;
                if (!n) return true;
                flowerbed[i] = 1;
            }
        }
        return false;
    }
};

621 任务调度器

贪心,按任务出现次数从最大到最小排布。

class Solution {
    
    
public:
    int leastInterval(vector<char>& tasks, int n) {
    
    
        vector<int> cnt(26, 0);
        for (int i = 0; i < tasks.size(); i++)
            cnt[tasks[i] - 'A']++;
        sort(cnt.begin(), cnt.end());
        int len = n * (cnt[25] - 1) + cnt[25];
        for (int i = 0; i < 25; i ++)
            if (cnt[i] == cnt[25]) len++;
        return max(len, static_cast<int>(tasks.size()));
    }
};

分治

23 合并 K 个升序链表

分治,每层合并相邻的两个链表。

class Solution {
    
    
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
    
    
        return mergeDivide(lists, 0, lists.size() - 1);
    }

    ListNode* mergeDivide(vector<ListNode*>& lists, int begin, int end) {
    
    
        if (begin == end) return lists[begin];
        if (begin > end) return nullptr;
        int mid = (begin + end) >> 1;
        return mergeList(mergeDivide(lists, begin, mid), mergeDivide(lists, mid + 1, end));
    }

    ListNode* mergeList(ListNode* list1, ListNode* list2) {
    
    
        ListNode* dummy = new ListNode(-1);
        ListNode* curr = dummy;
        ListNode* curr1 = list1;
        ListNode* curr2 = list2;
        while (curr1 && curr2) {
    
    
            if (curr1->val <= curr2->val) {
    
    
                curr->next = curr1;
                curr1 = curr1->next;
            } else {
    
    
                curr->next = curr2;
                curr2 = curr2->next;
            }
            curr = curr->next;
        }
        if (curr1) curr->next = curr1;
        if (curr2) curr->next = curr2;
        ListNode* merged = dummy->next;
        delete(dummy);
        return merged;
    }   
};

53 最大子数组和

f ( i ) f(i) f(i) 为以 i i i 位置结尾的最大子数组和,即求 max ⁡ { f ( i ) } i = 1 n − 1 \max\{f(i)\}_{i=1}^{n-1} max{ f(i)}i=1n1;不难发现 f ( i − 1 ) ≤ 0 f(i-1)\leq 0 f(i1)0 时, f ( i ) = n u m s [ i ] f(i)={\rm nums}[i] f(i)=nums[i]

class Solution {
    
    
public:
    int maxSubArray(vector<int>& nums) {
    
    
        int prev = 0, maxCurr = nums[0];
        for (int i = 0; i < nums.size(); i++) {
    
    
            prev = prev < 0 ? nums[i] : prev + nums[i];
            maxCurr = max(maxCurr, prev);
        }
        return maxCurr;
    }
};

148 排序链表

归并:①快慢指针法找到链表中间结点;②合并两个有序链表。
(注:分割链表时前链表尾指针需维护或指向空)

class Solution {
    
    
public:
    ListNode* sortList(ListNode* head) {
    
    
        return mergeSort(head);
    }

    ListNode* mergeSort(ListNode* head) {
    
    
        if (!head || !head->next) return head;
        ListNode* head1 = head;
        ListNode* mid = midNode(head);
        ListNode* head2 = mid->next;
        mid->next = nullptr;
        return mergeList(mergeSort(head1), mergeSort(head2));
    }

    ListNode* midNode(ListNode* head) {
    
    
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast->next && fast->next->next) {
    
    
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }

    ListNode* mergeList(ListNode* head1, ListNode* head2) {
    
    
        ListNode* dummy = new ListNode(-1);
        ListNode* curr = dummy;
        ListNode* curr1 = head1;
        ListNode* curr2 = head2;
        while (curr1 && curr2) {
    
    
            if (curr1->val <= curr2->val) {
    
    
                curr->next = curr1;
                curr1 = curr1->next;
            } else {
    
    
                curr->next = curr2;
                curr2 = curr2->next;
            }
            curr = curr->next;
        }
        if (curr1) curr->next = curr1;
        if (curr2) curr->next = curr2;
        ListNode* merged = dummy->next;
        delete(dummy);
        return merged;
    }    
};

327 区间和个数

对前缀和归并排序过程中使用滑动窗口计数。

class Solution {
    
    
public:
    vector<long> preSum{
    
    0};
    int mini, maxi;

    int countRangeSum(vector<int>& nums, int lower, int upper) {
    
    
        long sum = 0;
        for (int i = 0; i < nums.size(); i++) {
    
    
            sum += nums[i];
            preSum.push_back(sum);
        }
        mini = lower, maxi = upper;
        return mergeCnt(0, preSum.size() - 1);
    }

    int mergeCnt(int begin, int end) {
    
    
        if (begin == end) return 0;
        int mid = (begin + end) >> 1;
        int cnt = mergeCnt(begin, mid) + mergeCnt(mid + 1, end);

        int left = mid + 1, right = mid + 1;
        for (int i = begin; i <= mid; i++) {
    
    
            while (left <= end && preSum[left] - preSum[i] < mini) left++;
            while (right <= end && preSum[right] - preSum[i] <= maxi) right++;
            cnt += right - left;
        }

        vector<long> merged;
        left = begin, right = mid + 1;
        while (left <= mid && right <= end) {
    
    
            if (preSum[left] < preSum[right]) merged.push_back(preSum[left++]);
            else merged.push_back(preSum[right++]);
        }
        while (right <= end && left > mid) merged.push_back(preSum[right++]);
        while (left <= mid && right > end) merged.push_back(preSum[left++]);
        for (int i = 0; i < merged.size(); i++) preSum[begin + i] = merged[i];
        return cnt;
    }
};

654 最大二叉树

构造单调递减栈:入栈时,最后出栈的一定为左边最大值(最后出栈为当前结点的左孩子);若无出栈,待入栈的暂时作为右边的最大值(当前结点暂时为栈顶结点的右孩子)。栈顶结点一定是根节点(即最大值)。

class Solution {
    
    
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
    
    
        vector<int> stack;
        vector<TreeNode*> tree(int(nums.size()));
        for (int i = 0; i < nums.size(); ++i) {
    
    
            tree[i] = new TreeNode(nums[i]);
            // 单调递减栈, 数组下标入栈
            // 出栈至左边最大值作为当前节点左孩子
            while (!stack.empty() && nums[i] > nums[stack.back()]) {
    
    
                tree[i]->left = tree[stack.back()];
                stack.pop_back();
            }
            // 栈顶最终将右边最大值作为右孩子
            if (!stack.empty()) tree[stack.back()]->right = tree[i];
            // 当前结点入栈
            stack.push_back(i);
        }
        // 栈底一定为最大值(即根节点)
        return tree[stack[0]];
    }
};

回溯

46 全排列

回溯,全部数字选完时抵达叶子结点,载入记录每层剩余数字情况。

class Solution {
    
    
public:
    vector<vector<int>> allOrder;
    vector<int> order;

    vector<vector<int>> permute(vector<int>& nums) {
    
    
        allOrder.clear();
        order.clear();
        vector<bool> selected(nums.size(), false);
        backtracking(nums, selected);
        return allOrder;
    }

    void backtracking(vector<int>& nums, vector<bool>& selected) {
    
    
        if (order.size() == nums.size()) {
    
    
            allOrder.push_back(order);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
    
    
            if (selected[i]) continue;
            selected[i] = true;
            order.push_back(nums[i]);
            backtracking(nums, selected);
            order.pop_back();
            selected[i] = false;
        }
    }
};

51 N 皇后

回溯,以行为分支,列为深度;递归遍历时判断是否合法,仅当合法时写入Q;判断合法时仅需判断列、左上、右上。

class Solution {
    
    
public:
    vector<vector<string>> allOrder;

    vector<vector<string>> solveNQueens(int n) {
    
    
        allOrder.clear();
        vector<string> order(n, string(n, '.'));
        backtracking(n, 0, order);
        return allOrder;
    }

    void backtracking(int n, int raw, vector<string>& order) {
    
    
        if (raw == n) {
    
    
            allOrder.push_back(order);
            return;
        }
        for (int col = 0; col < n; col++) {
    
    
            if (isValid(n, raw, col, order)) {
    
    
                order[raw][col] = 'Q';
                backtracking(n, raw + 1, order);
                order[raw][col] = '.';
            }
        }
    }

    bool isValid(int n, int raw, int col, vector<string>& order) {
    
    
        for (int i = 0; i < raw; i++) if(order[i][col] == 'Q') return false;
        for (int i = raw - 1, j = col - 1; i >= 0 && j >=0; i--, j--)
            if (order[i][j] == 'Q') return false;
        for (int i = raw - 1, j = col + 1; i >= 0 && j <= n - 1; i--, j++)
            if (order[i][j] == 'Q') return false;
        return true;
    }
};

77 组合

回溯,全部数字选完时抵达叶子结点,载入遍历起点。

class Solution {
    
    
public:
    vector<vector<int>> result;
    vector<int> path;

    vector<vector<int>> combine(int n, int k) {
    
    
        result.clear();
        path.clear();
        backtracking(n, k, 1);
        return result;
    }

        void backtracking(int n, int k, int begin) {
    
    
        if (path.size() == k) {
    
    
            result.push_back(path);
            return;
        }
        for (int i = begin; i <= n; ++i) {
    
    
            path.push_back(i);
            backtracking(n, k, i + 1);
            path.pop_back();
        }
    }
};

95 不同的二叉搜索树 II

二叉搜索树左子树值一定都比根节点小,右子树值一定都比根节点大,由此进行递归。

class Solution {
    
    
public:
    vector<TreeNode*> generateTrees(int n) {
    
    
        if (!n) return {
    
    };
        return backtracking(1, n);
    }

    vector<TreeNode*> backtracking(int begin, int end) {
    
    
        if (begin > end) return {
    
    nullptr};
        vector<TreeNode*> subtree;
        for (int i = begin; i <= end; i++) {
    
    
            vector<TreeNode*> left = backtracking(begin, i - 1);
            vector<TreeNode*> right = backtracking(i + 1, end);
            for (int jl = 0; jl < left.size(); jl++) {
    
    
                for (int jr = 0; jr < right.size(); jr++) {
    
    
                    TreeNode* root = new TreeNode(i);
                    root->left = left[jl];
                    root->right = right[jr];
                    subtree.push_back(root);
                }
            }
        }
        return subtree;
    }
};

797 所有可能路径

DFS,深搜。

class Solution {
    
    
public:
    vector<vector<int>> allPath;
    vector<int> path;

    vector<vector<int>> allPathsSourceTarget(vector<vector<int>>& graph) {
    
    
        path.push_back(0);
        dfs(graph, 0, graph.size() - 1);
        return allPath;
    }

    void dfs(vector<vector<int>>& graph, int curr, int end) {
    
    
        if (curr == end) {
    
    
            allPath.push_back(path);
            return;
        }
        for (auto& next: graph[curr]) {
    
    
            path.push_back(next);
            dfs(graph, next, end);
            path.pop_back();
        }
    }
};

动态规划

62 不同路径

不难发现路径数为 ( n + m − 2 m − 1 ) = ( n + m − 2 n − 1 ) {n+m-2 \choose m-1}={n+m-2 \choose n-1} (m1n+m2)=(n1n+m2)

class Solution {
    
    
public:
    int uniquePaths(int m, int n) {
    
    
        long long cnt = 1;
        for (int i = n, j = 1; j < m; i++, j++) {
    
    
            cnt = cnt * i / j;
        }
        return cnt;
    }
};

70 爬楼梯

动规入门, f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n1)+f(n2)

class Solution {
    
    
public:
    int climbStairs(int n) {
    
    
        vector<int> dp(3);
        dp[0] = 0, dp[1] = 0, dp[2] = 1;
        for (int i = 0; i < n; i++) {
    
    
            dp[0] = dp[1], dp[1] = dp[2];
            dp[2] = dp[0] + dp[1];
        }
        return dp[2];
    }
};

120 三角形最小路径和

自下向上原地修改数组, f ( i , j ) = min ⁡ { f ( i + 1 , j ) , f ( i + 1 , j + 1 ) } + t r i [ i ] [ j ] f(i,j)=\min\{f(i+1,j),f(i+1,j+1)\}+{\rm tri}[i][j] f(i,j)=min{ f(i+1,j),f(i+1,j+1)}+tri[i][j];由于出发点唯一, f ( 0 , 0 ) f(0,0) f(0,0) 即为所求。

class Solution {
    
    
public:
    int minimumTotal(vector<vector<int>>& triangle) {
    
    
        for (int i = triangle.size() - 2; i >= 0; i--)
            for (int j = 0; j <= i; j ++)
                triangle[i][j] = min(triangle[i + 1][j], triangle[i + 1][j + 1]) + triangle[i][j];
        return triangle[0][0];
    }
};

124 二叉树中的最大路径和

回溯,叶子结点返回 0 0 0,根节点返回根值与左右子树值中最大的和。根节点处最大值可能为:①左右子树最大值与根值和;②子树中的最大值。

class Solution {
    
    
public:
    int maxPath = INT_MIN;

    int maxPathSum(TreeNode* root) {
    
    
        backtracking(root);
        return maxPath;
    }

    int backtracking(TreeNode* root) {
    
    
        if (!root) return 0;
        int maxLeft = max(backtracking(root->left), 0);
        int maxRight = max(backtracking(root->right), 0);
        maxPath = max(maxPath, root->val + maxLeft + maxRight);
        return root->val + max(maxLeft, maxRight);
    }
};

198 打家劫舍

动规, f ( i ) = max ⁡ { f ( i − 2 ) + n u m s [ i ] , f ( i − 1 ) } f(i)=\max\{f(i-2)+{\rm nums}[i],f(i-1)\} f(i)=max{ f(i2)+nums[i],f(i1)}

class Solution {
    
    
public:
    int rob(vector<int>& nums) {
    
    
        if (nums.empty()) return 0;
        if (nums.size() == 1) return nums[0];
        vector<int> dp(3);
        dp[0] = nums[0], dp[1] = max(nums[0], nums[1]);
        for (int i = 2; i < nums.size(); i++) {
    
    
            dp[2] = max(dp[0] + nums[i], dp[1]);
            dp[0] = dp[1], dp[1] = dp[2];
        }
        return dp[1];
    }
};

图论

310 最小高度树

拓扑排序,从度 “1” 结点开始删除(BFS),余下的至多两个结点即为所求。

class Solution {
    
    
public:
    vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
    
    
        if (n == 1) return {
    
    0};
        vector<int> degree(n);
        vector<vector<int>> edge(n);
        queue<int> queue;
        vector<int> root;
        for (auto &i : edges) {
    
    
            edge[i[0]].push_back(i[1]);
            edge[i[1]].push_back(i[0]);
            degree[i[0]]++;
            degree[i[1]]++;
        }
        for (int i = 0; i < n; i++) 
            if (degree[i] == 1) queue.push(i);
        int remains = n;
        while (remains > 2) {
    
    
            int size = queue.size();
            for (int i = 0; i < size; i++) {
    
    
                int curr = queue.front();
                for (auto &j : edge[curr]) {
    
    
                    degree[j]--;
                    if (degree[j] == 1) queue.push(j);
                }
                queue.pop();
            }
            remains -= size;
        }
        while (!queue.empty()) {
    
    
            root.push_back(queue.front());
            queue.pop();
        }
        return root;
    }
};

332 重新安排行程

有向图 Hierholzer 算法,遍历结点时倒序入栈,遍历过的边从边集中删去。

class Solution {
    
    
public:
    unordered_map<string, priority_queue<string, vector<string>, greater<string>>> edge;
    vector<string> stack;

    vector<string> findItinerary(vector<vector<string>>& tickets) {
    
    
        for (int i = 0; i < tickets.size(); i++)
            edge[tickets[i][0]].push(tickets[i][1]);
        hierholzer("JFK");

        reverse(stack.begin(), stack.end());
        return stack;
    }

    void hierholzer(string curr) {
    
    
        while(edge.count(curr) && !edge[curr].empty()) {
    
    
            string next = edge[curr].top();
            edge[curr].pop();
            hierholzer(next);
        }
        stack.push_back(curr);
    }
};

997 找到小镇的法官

图论入门,即找到入度为 n − 1 n-1 n1 的顶点。

class Solution {
    
    
public:
    int findJudge(int n, vector<vector<int>>& trust) {
    
    
        vector<int> degree(n + 1, 0);
        for (int i = 0; i < trust.size(); i++) {
    
    
            degree[trust[i][0]]--;
            degree[trust[i][1]]++;
        }
        for (int i = 1; i <= n; i++)
            if (degree[i] == n - 1) return i;
        return -1;
    }
};

1446 重新规划路线

构造邻接表,使用 “1” 标记原方向边,使用 “0” 标记反方向边;从 “0” 出发 dfs,遇到 “1” 边则修改数量 + 1 +1 +1

class Solution {
    
    
public:
    int minReorder(int n, vector<vector<int>>& connections) {
    
    
        vector<vector<pair<int, int>>> edges(n);
        for (auto e : connections) {
    
    
            edges[e[0]].push_back(make_pair(e[1], 1));
            edges[e[1]].push_back(make_pair(e[0], 0));
        }
        return dfs(0, -1, edges);
    }

    int dfs(int curr, int prev, vector<vector<pair<int, int>>>& edges) {
    
    
        int cnt = 0;
        for (auto& next : edges[curr])
            if (next.first != prev)
                cnt = cnt + next.second + dfs(next.first, curr, edges);
        return cnt;
    }
};

1615 最大网络秩

枚举。

class Solution {
    
    
public:
    int maximalNetworkRank(int n, vector<vector<int>>& roads) {
    
    
        vector<vector<bool>> connected(n, vector<bool>(n, false));
        vector<int> degree(n, 0);
        for (int i = 0; i < roads.size(); i++) {
    
    
            connected[roads[i][0]][roads[i][1]] = true;
            connected[roads[i][1]][roads[i][0]] = true;
            degree[roads[i][0]]++; degree[roads[i][1]]++;
        }
        int maxRank = 0;
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++)
                maxRank = max(maxRank, degree[i] + degree[j] - int(connected[i][j]));
        return maxRank;
    }
};

IO

上机测试需要自己补全IO,简单写一下IO模板以备用。

共同头文件及命名空间。

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

读取一行数据为vector

// 外部声明
// 整型
void get_line_vector_int(vector<int>& nums) {
    
    
	string line;
	getline(cin, line);
	istringstream iss(line);
	string buffer;
	while (getline(iss, buffer, ' '))
		nums.emplace_back(stoi(buffer));
}

// 字符型
void get_line_vector_int(vector<char>& chs) {
    
    
	string line;
	getline(cin, line);
	istringstream iss(line);
	string buffer;
	while (getline(iss, buffer, ' '))
		chs.emplace_back(buffer[0]);
}

读取一行数据为ListNode

// 标准单链表(无哨兵结点)
struct ListNode{
    
    
	int val;
	ListNode *next;
	explicit ListNode(int x) : val(x), next(nullptr){
    
    }
};

// 返回头指针
ListNode* get_line_list_int() {
    
    
	string line;
	getline(cin, line);
	istringstream iss(line);
	string buffer;
	ListNode* tail = new ListNode(-1);
	ListNode* dummy = tail;
	while (getline(iss, buffer, ' ')) {
    
    
		tail->next = new ListNode(stoi(buffer));
		tail = tail->next;
	}
	ListNode* head = dummy->next;
	delete(dummy);
	return head;
}

读取一行数据为TreeNode(层次)

// 标准二叉树
struct TreeNode {
    
    
	int val;
	TreeNode *left;
	TreeNode *right;
	explicit TreeNode(int x) : val(x), left(nullptr), right(nullptr) {
    
    }
};

// 选择取值范围外的数值作为空指针标志
const int null = 1001;

// 由精简数组构造二叉树
TreeNode* create_tree(vector<int>& tree, int pos) {
    
    
	if (pos >= tree.size() || tree[pos] >= null) return nullptr;
	TreeNode* root = new TreeNode(tree[pos]);
	root->left = create_tree(tree, pos << 1);
	root->right = create_tree(tree, (pos << 1) + 1);
	return root;
}

// 返回根结点
TreeNode* get_line_tree_int() {
    
    
	// 读入一行数据
	string line;
	getline(cin, line);
	istringstream iss(line);
	string buffer;
	vector<int> tree;
	tree.emplace_back(null);
	while (getline(iss, buffer, ' '))
		tree.emplace_back(stoi(buffer));

	TreeNode* root = create_tree(tree, 1);
	return root;
}

读取多行数据为vector<vector>

// 外部声明
// 整型
void get_lines_vector_vector_int(vector<vector<int>>& nums) {
    
    
	string line;
	while (getline(cin, line)) {
    
    
		istringstream iss(line);
		string buffer;
		vector<int> raw;
		while (getline(iss, buffer, ' '))
			raw.emplace_back(stoi(buffer));
		nums.emplace_back(raw);
	}
}

// 字符串型
void get_lines_vector_vector_str(vector<vector<string>>& nums) {
    
    
	string line;
	while (getline(cin, line)) {
    
    
		istringstream iss(line);
		string buffer;
		vector<string> raw;
		while (getline(iss, buffer, ' ')) {
    
    
			raw.emplace_back(buffer);
		}
		nums.emplace_back(raw);
	}
}

读取多行数据为vector<ListNode>

// 外部声明
void get_lines_vector_list(vector<ListNode*>& nums) {
    
    
	string line;
	while (getline(cin, line)) {
    
    
		istringstream iss(line);
		string buffer;
		ListNode* tail = new ListNode(-1);
		ListNode* dummy = tail;
		while (getline(iss, buffer, ' ')) {
    
    
			tail->next = new ListNode(stoi(buffer));
			tail = tail->next;
		}
		ListNode* head = dummy->next;
		delete(dummy);
		nums.emplace_back(head);
	}
}

vector<ListNode>输出

void put_lines_vector_list(vector<ListNode*>& res) {
    
    
	for (auto list : res) {
    
    
		for (ListNode* curr = list; curr; curr = curr->next)
			cout << curr->val << ' ';
		cout << endl;
	}
}

vector<string>输出

void put_lines_vector_string(vector<string>& res) {
    
    
	for (auto& str : res) cout << str << endl;
}

猜你喜欢

转载自blog.csdn.net/annesede/article/details/142236363