文章目录
🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨
题目一:盛最多水的容器
题目描述:
给定 n 个非负整数 a1,a2,…,an,每个数代表一个坐标点 (i, ai) 。在坐标内画 n 条垂直线,使得 i 垂直线的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴构成的容器可以容纳最多的水。
题目分析:
这是一个典型的双指针问题。我们可以使用两个指针分别指向数组的首尾,然后计算当前两个指针所构成的容器的面积。接着,我们移动指向较短线段的指针(因为容器的高度由较短的线段决定,移动较长线段的指针无法增加容器的高度,而只会减少容器的宽度),直到两个指针相遇。
解题思路:
初始化两个指针,一个指向数组的开始,另一个指向数组的末尾。
计算当前两个指针所构成的容器的面积,并更新最大面积。
移动指向较短线段的指针。
重复步骤2和3,直到两个指针相遇。
返回最大面积。
示例代码:
#include <stdio.h>
// 函数声明
int maxArea(int* height, int heightSize);
int main() {
int height[] = {1,8,6,2,5,4,8,3,7};
int heightSize = sizeof(height) / sizeof(height[0]);
int result = maxArea(height, heightSize);
printf("Maximum area: %d\n", result);
return 0;
}
// 计算最大容器面积的函数实现
int maxArea(int* height, int heightSize) {
int max_area = 0;
int left = 0;
int right = heightSize - 1;
while (left < right) {
// 计算当前容器的面积
int current_area = (right - left) * ((height[left] < height[right]) ? height[left] : height[right]);
// 更新最大面积
if (current_area > max_area) {
max_area = current_area;
}
// 移动指向较短线段的指针
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return max_area;
}
深入剖析:
该算法的时间复杂度为O(n),因为我们只遍历了数组一次。空间复杂度为O(1),因为我们只使用了常数级别的额外空间。这种双指针的技巧在处理类似问题时非常有用,特别是当问题涉及到数组或链表的两端时。
题目二:最长无重复字符的子串
题目描述:
给定一个字符串,找出其中没有重复字符的最长子串的长度。
题目分析:
这是一个滑动窗口问题。我们可以使用两个指针来定义一个窗口,窗口内的字符都是唯一的。当遇到重复字符时,我们移动左指针来缩小窗口,直到窗口内没有重复字符为止。同时,我们需要一个哈希表来记录每个字符在窗口中的位置,以便在O(1)时间内判断字符是否重复。
解题思路:
初始化两个指针(left和right)和一个哈希表(用于记录字符的位置)。
使用right指针扩展窗口,直到遇到重复字符。
当遇到重复字符时,移动left指针缩小窗口,直到窗口内没有重复字符。
在每次移动窗口后,更新最大长度。
重复步骤2-4,直到right指针到达字符串的末尾。
返回最大长度。
示例代码:
#include <stdio.h>
#include <string.h>
// 函数声明
int lengthOfLongestSubstring(char * s);
int main() {
char s[] = "abcabcbb";
int result = lengthOfLongestSubstring(s);
printf("Length of longest substring without repeating characters: %d\n", result);
return 0;
}
// 计算最长无重复字符子串长度的函数实现
int lengthOfLongestSubstring(char * s) {
int n = strlen(s);
if (n == 0) {
return 0;
}
int max_len = 0;
int left = 0;
int right = 0;
int char_map[256] = { -1 }; // 假设输入字符为ASCII码
while (right < n) {
if (char_map[s[right]] != -1) {
// 遇到重复字符,移动左指针
left = (char_map[s[right]] + 1 > left) ? char_map[s[right]] + 1 : left;
}
// 更新字符的位置
char_map[s[right]] = right;
// 更新最大长度
max_len = (right - left + 1 > max_len) ? right - left + 1 : max_len;
// 移动右指针
right++;
}
return max_len;
}
深入剖析:
该算法的时间复杂度为O(n),因为我们只遍历了字符串一次。空间复杂度为O(1)(如果考虑哈希表的大小为常数,因为ASCII码字符集是有限的),但实际上哈希表的大小取决于字符集的大小,对于Unicode字符集,空间复杂度会稍大一些。滑动窗口技巧在处理子串、子数组相关问题时非常有效。
题目三:合并区间
题目描述:
给出一个区间的集合,请合并所有重叠的部分。
题目分析:
这是一个排序和合并问题。首先,我们需要对区间按照起始位置进行排序。然后,我们遍历排序后的区间列表,使用一个变量来跟踪当前的合并区间。如果下一个区间的起始位置小于或等于当前合并区间的结束位置,则将它们合并;否则,将当前合并区间添加到结果列表中,并更新合并区间为下一个区间。
解题思路:
对区间按照起始位置进行排序。
初始化一个空的结果列表和一个变量来跟踪当前的合并区间。
遍历排序后的区间列表:
如果当前区间与合并区间重叠,则合并它们。
否则,将合并区间添加到结果列表中,并更新合并区间为当前区间。
将最后一个合并区间添加到结果列表中。
返回结果列表。
示例代码:
#include <stdio.h>
#include <stdlib.h>
// 区间结构体定义
typedef struct {
int start;
int end;
} Interval;
// 比较函数,用于qsort排序
int compare(const void *a, const void *b) {
Interval *intervalA = (Interval *)a;
Interval *intervalB = (Interval *)b;
return intervalA->start - intervalB->start;
}
// 合并区间的函数声明
Interval* merge(Interval* intervals, int intervalsSize, int* returnSize);
int main() {
Interval intervals[] = {{1, 3}, {2, 6}, {8, 10}, {15, 18}};
int intervalsSize = sizeof(intervals) / sizeof(intervals[0]);
int returnSize = 0;
Interval* result = merge(intervals, intervalsSize, &returnSize);
printf("Merged intervals:\n");
for (int i = 0; i < returnSize; i++) {
printf("[%d, %d] ", result[i].start, result[i].end);
}
printf("\n");
// 释放动态分配的内存
free(result);
return 0;
}
// 合并区间的函数实现
Interval* merge(Interval* intervals, int intervalsSize, int* returnSize) {
if (intervalsSize == 0) {
*returnSize = 0;
return NULL;
}
// 按照起始位置排序区间
qsort(intervals, intervalsSize, sizeof(Interval), compare);
// 动态分配结果数组的内存
Interval* merged = (Interval*)malloc(intervalsSize * sizeof(Interval));
*returnSize = 0;
// 初始化当前合并区间
Interval current = intervals[0];
for (int i = 1; i < intervalsSize; i++) {
if (intervals[i].start <= current.end) {
// 当前区间与合并区间重叠,合并它们
current.end = (intervals[i].end > current.end) ? intervals[i].end : current.end;
} else {
// 当前区间与合并区间不重叠,将合并区间添加到结果列表中,并更新合并区间
merged[*returnSize] = current;
(*returnSize)++;
current = intervals[i];
}
}
// 添加最后一个合并区间到结果列表中
merged[*returnSize] = current;
(*returnSize)++;
return merged;
}
深入剖析:
该算法的时间复杂度为O(n log n),其中n是区间的数量,因为我们需要对区间进行排序。空间复杂度为O(n),因为我们需要动态分配一个与区间数量相等大小的结果数组。合并区间的技巧在处理类似问题时非常有用,特别是当问题涉及到重叠区间的合并、求并集等操作时。
✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊
🏠 我在CSDN等你哦!我的主页😍