五月集训(第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;
}
};
东方欲晓,莫道君行早。