五月集训(第29天)—分而治之

分而治之

1. 21. 合并两个有序链表

    思路:
        两个链表分别比较,递归合并两链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
        if (list1 == nullptr) return list2;
        if (list2 == nullptr) return list1;

        ListNode *head = new ListNode();

        if (list1->val < list2->val) {
            head->val = list1->val;
            head->next = mergeTwoLists(list1->next, list2);
        } else {
            head->val = list2->val;
            head->next = mergeTwoLists(list1, list2->next);
        }
        return head;
    }
};

2. 1985. 找出数组中的第 K 大整数

    思路:
        对nums按照降序,归并排序,返回第k个值。

class Solution {
    bool is_bigger(const string &a, const string &b) {
        int len_a = a.length(), len_b = b.length();
        if (len_a != len_b) return len_a > len_b;
        return a > b;
    }

    void mergesort(vector<string> &nums, int l, int r) {
        if (l >= r) return ;
        int mid = l + ((r - l) >> 1);
        // 归并
        mergesort(nums, l, mid);
        mergesort(nums, mid + 1, r);
        vector<string> temp;
        int i = l, j = mid + 1;
        while (i <= mid || j <= r) {
            if (i == mid + 1) temp.emplace_back(nums[j++]);     /* 左边拍完了,直接把右边剩下的放入 */
            else if (j == r + 1) temp.emplace_back(nums[i++]);   /* 右边拍完了,直接把左边剩下的放入 */
            else {  /* 左右依次比较取较大值 */
                if (is_bigger(nums[j], nums[i])) temp.emplace_back(nums[j++]);
                else temp.emplace_back(nums[i++]);
            }
        }
        /* 将nums局部完成升序排列,返回上一层,作为上一层继续归并 */
        for (int idx = l; idx <= r; ++idx) {
            nums[idx] = temp[idx - l];
        }
    }
public:
    string kthLargestNumber(vector<string>& nums, int k) {
        mergesort(nums, 0, nums.size() - 1);
        return nums[k - 1];
    }
};

3. 558. 四叉树交集

    思路:
        利用分治的思想,将大问题拆解为2种情况逐个解决。
        (1) 有一个是叶子结点,则根据逻辑或运算,直接返回叶子节点即可,否则返回另一个结点,继续递归处理
        (2) 两个都不是叶子结点时,判断其子节点
                (2.1) 两个都不是叶子结点,但是四个子节点的val值都为true,且都为叶子结点,则合并为一个新的叶子节点
                (2.2) 两个都不是叶子结点,且四个子结点的值不都为true,或四子节点val不都为false,则根据逻辑或的关系,带着子节点作为答案返回即可。

/*
// Definition for a QuadTree node.
class Node {
public:
    bool val;
    bool isLeaf;
    Node* topLeft;
    Node* topRight;
    Node* bottomLeft;
    Node* bottomRight;
    
    Node() {
        val = false;
        isLeaf = false;
        topLeft = NULL;
        topRight = NULL;
        bottomLeft = NULL;
        bottomRight = NULL;
    }
    
    Node(bool _val, bool _isLeaf) {
        val = _val;
        isLeaf = _isLeaf;
        topLeft = NULL;
        topRight = NULL;
        bottomLeft = NULL;
        bottomRight = NULL;
    }
    
    Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) {
        val = _val;
        isLeaf = _isLeaf;
        topLeft = _topLeft;
        topRight = _topRight;
        bottomLeft = _bottomLeft;
        bottomRight = _bottomRight;
    }
};
*/

class Solution {
public:
    Node* intersect(Node* quadTree1, Node* quadTree2) {
    	// (1)
        if (quadTree1->isLeaf) {
            if (quadTree1->val) return quadTree1;
            else return quadTree2;
        }  
        if (quadTree2->isLeaf) {
            if (quadTree2->val) return quadTree2;
            else return quadTree1;
        }
        // (2)都不为叶子节点时,分别递归获取四个方向的结点
        Node *topLeft = intersect(quadTree1->topLeft, quadTree2->topLeft);
        Node *topRight = intersect(quadTree1->topRight, quadTree2->topRight);
        Node *bottomLeft = intersect(quadTree1->bottomLeft, quadTree2->bottomLeft);
        Node *bottomRight = intersect(quadTree1->bottomRight, quadTree2->bottomRight);

		// (2.1)如果四个节点同时为叶子节点。并且值为true时,则返回的节点进行合并,合并为一个值为true的叶子节点
		if (topLeft->isLeaf && topRight->isLeaf && bottomLeft->isLeaf && bottomRight->isLeaf &&
			topLeft->val && topRight->val && bottomLeft->val && bottomRight->val) {
			return new Node(true, true, NULL, NULL, NULL, NULL);
		}
        // (2.2)不是叶节点,且val为false的情况,返回的结点不能合并
        return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight);
    }
};

4. 932. 漂亮数组

    思路:
        将数组拆成两个,左边放奇数,右边放偶数,此时从左边和右边各取一个数,其和为奇数所以满足条件。
        继续将左右数组以同样的方法,跳项拆为两个数组,奇数之和为偶数,偶数之和为奇数,所以不可能有A[k] * 2 = A[i] + A[j]
        那么问题就可以利用分治的方法解决了,不停的跳项拆分数组,当数组的长度小于等于2时停止拆分,代码实现如下。

class Solution {
    void split(vector<int> &arr) {
        int arr_size = arr.size(), i;
        if (arr_size <= 2) return ;

        vector<int> left;
        vector<int> right;
        for (i = 0; i < arr_size; i += 2) left.push_back(arr[i]);
        for (i = 1; i < arr_size; i += 2) right.push_back(arr[i]);
        split(left);
        split(right);
        
        int idx = 0;
        int left_size = left.size();
        int right_size = right.size();
        for (i = 0; i < left_size; ++i) arr[idx++] = left[i];
        for (i = 0; i < right_size; ++i) arr[idx++] = right[i];
    }
public:
    vector<int> beautifulArray(int n) {
        vector<int> ans;
        int i;
        for (i = 1; i <= n; ++i) {
            ans.push_back(i);
        }
        split(ans);
        return ans;
    }
};
posted @ 2022-06-04 13:23  番茄元  阅读(20)  评论(0)    收藏  举报