题源:LeetCode
LeetCode每日一题:
1725. 可以形成最大正方形的矩形数目
给你一个数组 rectangles ,其中 rectangles[i] = [li, wi] 表示第 i 个矩形的长度为 li 、宽度为 wi 。
如果存在 k 同时满足 k <= li 和 k <= wi ,就可以将第 i 个矩形切成边长为 k 的正方形。例如,矩形 [4,6] 可以切成边长最大为 4 的正方形。
设 maxLen 为可以从矩形数组 rectangles 切分得到的 最大正方形 的边长。
请你统计有多少个矩形能够切出边长为 maxLen 的正方形,并返回矩形 数目 。
示例 1:
输入:rectangles = [[5,8],[3,9],[5,12],[16,5]]
输出:3
解释:能从每个矩形中切出的最大正方形边长分别是 [5,3,5,5] 。
最大正方形的边长为 5 ,可以由 3 个矩形切分得到。
示例 2:
输入:rectangles = [[2,3],[3,7],[4,3],[3,7]]
输出:3
提示:
1 <= rectangles.length <= 1000
rectangles[i].length == 2
1 <= li, wi <= 109
li != wi
class Solution {
public:
int countGoodRectangles(vector<vector<int>>& rectangles) {
int res = 0, maxLen = 0;
for(auto & rectangle : rectangles){
int l = rectangle[0], w = rectangle[1];
int k = min(l, w);
if(k == maxLen){
res++;
}else if(k > maxLen){
res = 1;
maxLen = k;
}
}
return res;
}
};
143. 重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
提示:
链表的长度范围为 [1, 5 * 104]
1 <= node.val <= 1000
方法一:线性表
因为链表不支持下标访问,所以我们无法随机访问链表中任意位置的元素。
因此比较容易想到的一个方法是,我们利用线性表存储该链表,然后利用线性表可以下标访问的特点,直接按顺序访问指定元素,重建该链表即可。
class Solution {
public:
void reorderList(ListNode *head) {
if (head == nullptr) return;
//利用线性表存储该链表
vector<ListNode *> vec;
ListNode *node = head;
while (node != nullptr) {
vec.emplace_back(node);
node = node->next;
}
//利用线性表可以下标访问的特点,直接按顺序访问指定元素,重建该链表即可
int i = 0, j = vec.size() - 1;
while (i < j) {
vec[i]->next = vec[j];
i++;
if (i == j) break;
vec[j]->next = vec[i];
j--;
}
vec[i]->next = nullptr;
}
};
复杂度分析
时间复杂度:O(N),其中 N 是链表中的节点数。
空间复杂度:O(N),其中 N 是链表中的节点数。主要为线性表的开销。
方法二:寻找链表中点 + 链表逆序 + 合并链表
注意到目标链表即为将原链表的左半端和反转后的右半端合并后的结果。
这样我们的任务即可划分为三步:
-
找到原链表的中点(参考「876. 链表的中间结点」)。
- 我们可以使用快慢指针来 O(N)O(N)O(N) 地找到链表的中间节点。
-
将原链表的右半端反转(参考「206. 反转链表」)。
- 我们可以使用迭代法实现链表的反转。
-
将原链表的两端合并。
- 因为两链表长度相差不超过 1,因此直接合并即可。
/**
* 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* middleNode(ListNode* head){
ListNode* slow = head;
ListNode* fast = head;
while(fast->next != NULL && fast->next->next != NULL){
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
ListNode* reverseList(ListNode* head){
ListNode* prev = NULL;
ListNode* curr = head;
while(curr != NULL){
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
void mergeList(ListNode* l1, ListNode* l2){
ListNode* l1_tmp;
ListNode* l2_tmp;
while(l1 != NULL && l2 != NULL){
l1_tmp = l1->next;
l2_tmp = l2->next;
l1->next = l2;
l1 = l1_tmp;
l2->next = l1;
l2 = l2_tmp;
}
}
void reorderList(ListNode* head) {
if(head == NULL) return;
ListNode* mid = middleNode(head);//寻找链表中点
ListNode* l1 = head;
ListNode* l2 = mid->next;
mid->next = NULL;
l2 = reverseList(l2);//将原链表的右半端反转
mergeList(l1, l2);//将原链表的两端合并
}
};
复杂度分析
- 时间复杂度:O(N),其中 N 是链表中的节点数。
- 空间复杂度:O(1)。