• leetcode刷题(二)


    92. 反转链表 II

    反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

    题解

    两个思路:①不断调换指针②不断交换值。因为(m)可能等于1,所以要添加一个头节点(好写)

    用循环比用while方便多了,还不容易出bug

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution {
    public:
        ListNode* reverseBetween(ListNode* head, int m, int n) {
    
            ListNode* root = new ListNode(0);    // 加一个头节点很方便
            root->next = head;
    
            ListNode* copy_head = root;
    
            for (int i = 1; i < m; ++i) root = root->next;
            /*  
            与for循环的功能一样,找出翻转位置的前一个节点
            注意:index++;不要放错位置!!!
    
            int index = 0;
            while(root->next != NULL) {
                if (index + 1 >= m) break;
                root = root->next;
                index++;
            }
            */
            head = root->next;
            for (int i = m; i < n; ++i) {
                ListNode* temp = root->next;
    
                root->next = head->next;
                head->next = head->next->next;
                root->next->next = temp;
            }
    
            return copy_head->next;
            /*
            同上面的for循环一样的功能
            ListNode* start = root;
            head = root->next;
    
            int cnt = 0;
            while(head->next != NULL) {
                ++cnt;
                if (cnt == n - m + 1) break;
                ListNode* temp = start->next;
    
                start->next = head->next;
                head->next = head->next->next;
                start->next->next = temp;
            }
    
            return copy_head->next;
            */
        }
    };
    

    765. 情侣牵手

    N 对情侣坐在连续排列的 2N 个座位上,想要牵到对方的手。 计算最少交换座位的次数,以便每对情侣可以并肩坐在一起。 一次交换可选择任意两人,让他们站起来交换座位。

    人和座位用 0 到 2N-1 的整数表示,情侣们按顺序编号,第一对是 (0, 1),第二对是 (2, 3),以此类推,最后一对是 (2N-2, 2N-1)。

    这些情侣的初始座位 row[i] 是由最初始坐在第 i 个座位上的人决定的。

    题解一

    这道题蕴含了一个经常拿来出题的考点:对于任意一个排列,按照下标建边构成的图由一个个不相交的循环组成。举例来说:[3, 1, 0, 2],按照上述方式构图有两个循环:(0 ightarrow 3 ightarrow 2 ightarrow 0)(1 ightarrow 1)(自循环)。

    先思考这样一个问题:Meeting with Aliens UVA - 10570,(n)个数的排列,一次操作选任意两个数进行交换,问使得排列变为升序或者降序的最少操作次数?

    排列按照上述方式构图后如果只由一个循环组成,比如[2, 3, 1, 0]这样一个排列,那么所需交换次数最少为环中节点个数减一,既(op_{min} = n - 1)。如果由多个环构成,假设环的个数为(t),每个环的节点个数为(cnt_i),那么所需交换次数最少为(sum_{i = 0}^t (cnt_i - 1)),整理哈,既(op_{min} = n - t)

    有兴趣的童鞋可以尝试用数学归纳法证明单个循环的情况(黑体字部分),注意:两个环之间不需要交换操作,既只在环内进行交换操作。因为交换到另一个环后,最终又要交换回来,毕竟它在升序或者降序中的位置就在刚开始的环上。

    对于这道题,很容易想到先把情侣的一人固定在当前位置上,然后交换另一个人来凑成情侣。复杂度(O(n^2)),空间复杂度(O(1))

    class Solution {
    public:
        int minSwapsCouples(vector<int>& row) {
            int n = row.size();
            int ans = 0;
            
            for (int i = 0; i < n; i += 2) {
                if (judeg(row[i],  row[i + 1])) continue;
                for (int j = i + 2; j < n; j += 2) {
                    if (judeg(row[j], row[j + 1])) continue;
                    if (judeg(row[i], row[j])) {
                        swap(row[i + 1], row[j]);
                        ans++;
                        break;
                    }
                    else if (judeg(row[i], row[j + 1])) {
                        swap(row[i + 1], row[j + 1]);
                        ans++;
                        break;
                    }
                }
            }
    
            return ans;
        }
        bool judeg(int a, int b) {
            if (a > b) swap(a, b);
            if (b - a > 1) return false;
            if (!(a & 1) && (b & 1)) return true;
            return false;
        }
    };
    

    第二个循环的作用是找它的配偶所在位置并交换,所以用一个数组记录一下,每个人的位置。时间复杂度(O(n)),空间复杂度(O(n)).

    这叫有失有得,另外,学习优化代码可重要了

    class Solution {
    public:
        int minSwapsCouples(vector<int>& row) 
        {
            int n = row.size(), ans = 0;
            vector<int> pos(n, -1);
    
            for (int i = 0; i < n; ++i) pos[row[i]] = i;
    
            for (int i = 0; i < n; i += 2) {
                int wife = row[i] ^ 1;
                if (wife != row[i + 1]) {
                    int id = pos[wife];
                    swap(row[i + 1], row[id]);
                    pos[row[id]] = id;
                    ans++;
                }
            }
            return ans;
        }
    };
    
  • 相关阅读:
    算法
    UVA 10318 Security Panel(DFS剪枝 + 状压 + 思维)题解
    CodeForces 509C Sums of Digits(贪心乱搞)题解
    UVA 10382 Watering Grass(区间覆盖,贪心)题解
    CodeForces 430A Points and Segments (easy)(构造)题解
    CodeForces 459C Pashmak and Buses(构造)题解
    newcoder F石头剪刀布(DFS + 思维)题解
    newcoder H肥猪(单调队列 / 线段树)题解
    UVALive 7501 Business Cycle(二分)题解
    UVALive 7503 Change(乱搞)题解
  • 原文地址:https://www.cnblogs.com/zgglj-com/p/12766564.html
Copyright © 2020-2023  润新知