6.输入一个非递减排列的整数数组nums,和一个目标值target。请找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值target,则输出0,0。请设计一个时间复杂度为0(log n)的算法解决此问题。
输入包括两行,第一行输入两个整数,分别表示数组的长度和target,第二行输入数组nums。输出为一个整数。
例如输入:
6 8
5 7 7 8 8 10
则输出: 4 5
若输入:
6 9
5 7 7 8 8 10
则输出: 0 0
#include <stdio.h>
// 二分查找的变种,用于找到目标值的左边界
int findLeftBound(int* nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
int leftBound = -1; // 初始化左边界为-1,表示未找到
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] >= target) {
right = mid - 1; // 尝试在左半部分查找
leftBound = mid; // 更新左边界
} else {
left = mid + 1;
}
}
return leftBound;
}
// 二分查找的变种,用于找到目标值的右边界
int findRightBound(int* nums, int numsSize, int target) {
int left = 0, right = numsSize - 1;
int rightBound = -1; // 初始化右边界为-1,表示未找到
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] <= target) {
left = mid + 1; // 尝试在右半部分查找
rightBound = mid; // 更新右边界
} else {
right = mid - 1;
}
}
return rightBound;
}
int main() {
int numsSize, target;
scanf("%d %d", &numsSize, &target);
int nums[numsSize];
for (int i = 0; i < numsSize; i++) {
scanf("%d", &nums[i]);
}
int leftBound = findLeftBound(nums, numsSize, target);
int rightBound = findRightBound(nums, numsSize, target);
// 如果左边界仍为-1,说明未找到目标值
if (leftBound == -1) {
printf("0 0\n");
} else {
printf("%d %d\n", leftBound + 1, rightBound + 1); // 数组索引从0开始,输出从1开始
}
return 0;
}
解释和步骤:
函数
findStartIndex
:
- 使用修改版的二分查找来找到目标值在数组中的起始位置。
- 初始化左右边界,然后在循环中根据中间元素与目标值的比较调整左右边界。
- 如果找到目标值,更新
start
并继续向左查找。函数
findEndIndex
:
- 使用同样的修改版二分查找来找到目标值在数组中的结束位置。
- 初始化左右边界,然后在循环中根据中间元素与目标值的比较调整左右边界。
- 如果找到目标值,更新
end
并继续向右查找。主函数
main
:
- 输入数组的长度和目标值。
- 输入排序后的整数数组。
- 调用
findStartIndex
和findEndIndex
函数找到目标值的起始位置和结束位置。- 如果找到了起始位置和结束位置,则输出它们;否则输出 "0 0" 表示目标值不存在于数组中。
运行结果:
7. 残缺棋盘是一个有2k×2k (k≥1)个方格的棋盘,其中恰有一个方格残缺。 下图给出k=1时各种可能的残缺棋盘,其中残缺的方格用阴影表示。
图中的棋盘称作“三格板”,残缺棋盘问题就是用这四种三格板覆盖更大的残缺棋盘。在覆盖中要求: 1)两个三格板不能重叠 2)三格板不能覆盖残缺方格,但必须覆盖其他所有方格 编程输入k及残缺格的坐标,求残缺棋盘覆盖方法。 输入:三个整数,分别表示k值和残缺格的坐标; 输出:2k×2k矩阵,具体数值为覆盖的序号。
#include<stdio.h>
#include<math.h>
void TileBoard(int tr,int tc,int dr,int dc,int size);
void OutputBoard(int size);
int tile=1;
int Board[1025][1025];
int main()
{
int n,a,b;
scanf("%d",&n);
int sum;
sum=pow(2,n);
scanf("%d %d",&a,&b);
Board[n][n]=0;
TileBoard(0,0,a,b,sum);
OutputBoard(sum);
return 0;
}
void TileBoard(int tr,int tc,int dr,int dc,int size)
{
if(size==1) return;
int t=tile++,
s=size/2;
if(dr<tr+s&&dc<tc+s)
TileBoard(tr,tc,dr,dc,s);
else
{
Board[tr+s-1][tc+s-1]=t;
TileBoard(tr,tc,tr+s-1,tc+s-1,s);
}
if(dr<tr+s&&dc>=tc+s)
TileBoard(tr,tc+s,dr,dc,s);
else
{
Board[tr+s-1][tc+s]=t;
TileBoard(tr,tc+s,tr+s-1,tc+s,s);
}
if(dr>=tr+s&&dc<tc+s)
TileBoard(tr+s,tc,dr,dc,s);
else
{
Board[tr+s][tc+s-1]=t;
TileBoard(tr+s,tc,tr+s,tc+s-1,s);
}
if(dr>=tr+s&&dc>=tc+s)
TileBoard(tr+s,tc+s,dr,dc,s);
else
{
Board[tr+s][tc+s]=t;
TileBoard(tr+s,tc+s,tr+s,tc+s,s);
}
}
void OutputBoard(int size)
{
for(int i=0;i<size;i++)
{
for(int j=0;j<size;j++){
printf("%-3d",Board[i][j]);
}
printf("\n");
}
printf("end");
}
运行结果:
8. 活动安排问题求解: 假设某社团某一天要组织n个活动E={1,2,3...n},其中每个活动都要求使用同一礼堂,而且在同一时间内只有一个活动能使用这个礼堂。每个活动i都有一个要求使用礼堂的起始时间si和结束时间fi, 且有si<fi,。若区间(si,fi,)和(sj,fj,)不相交,则称活动i与活动j是相容的。
现在给定n个活动的开始时间和结束时间,请设计一个活动安排方案,使得安排的相容活动数目最多。
表1 活动时间表
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 |
1 | 2 | 0 | 5 | 3 | 5 | 6 | 8 | 2 | 12 | 15 |
3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | 13 | 14 | 18 |
#include <stdio.h>
#include <stdlib.h>
// 定义活动结构体,包含活动的索引、开始时间和结束时间
struct Activity {
int index; // 活动的索引或编号
int start; // 活动的开始时间
int end; // 活动的结束时间
};
// 比较函数,用于qsort,根据活动的结束时间进行排序
// 返回值小于0表示a小于b,大于0表示a大于b,等于0表示a等于b
int compare(const void *a, const void *b) {
struct Activity *activityA = (struct Activity *)a; // 将void指针转换为Activity指针
struct Activity *activityB = (struct Activity *)b; // 将void指针转换为Activity指针
return (activityA->end - activityB->end); // 返回两个活动结束时间的差值
}
int main() {
int n = 12; // 活动的总数
// 初始化活动数组
struct Activity activities[] = {
{1, 1, 3},
{2, 12, 14},
{3, 0, 5},
{4, 5, 7},
{5, 6, 10},
{6, 3, 8},
{7, 8, 12},
{8, 5, 9},
{9, 8, 11},
{10, 2, 13},
{11, 2, 4},
{12, 15, 18}
};
// 使用qsort函数对活动数组进行排序,根据活动的结束时间
qsort(activities, n, sizeof(struct Activity), compare);
// 初始化计数器,用于记录被安排的活动数量
int counter = 1; // 至少可以安排一个活动
// 初始化最后一个已安排活动的结束时间
int last_end_time = activities[0].end; // 第一个活动的结束时间
// 打印第一个被安排的活动
printf("第%d个活动被安排: %d开始, %d结束.\n", activities[0].index, activities[0].start, activities[0].end);
// 遍历剩余的活动,尝试安排它们
for (int i = 1; i < n; i++) {
// 如果当前活动的开始时间不小于上一个已安排活动的结束时间,则可以安排
if (activities[i].start >= last_end_time) {
counter++; // 增加计数器
printf("第%d个活动被安排: %d开始, %d结束.\n", activities[i].index, activities[i].start, activities[i].end);
// 更新最后一个已安排活动的结束时间
last_end_time = activities[i].end;
}
}
// 打印总计被安排的活动数量
printf("总计%d个活动被安排\n", counter);
return 0;
}
运行结果:
9. 设有n个独立的作业{1,2…,n},由m台相同的机器进行加工处理。作业i所需时间为Ti。约定任何作业可以在任何一台机器上加工处理,但未完工前不允许中断处理,任何作业不能拆分成更小的子作业。要求给出一种作业调度方案,使所给的n个作业在尽可能短的时间内由m台机器加工处理完成。输入第一行输入n和m;第二行输入n个整数,分别表示n个作业做需要的时间,输出结果为一个整数,表示完成任务的最短时间。
#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于排序作业
int compare(const void *a, const void *b) {
return (*(int*)b - *(int*)a);
}
// 计算完成任务的最短时间
int shortestCompletionTime(int n, int m, int jobs[]) {
// 按处理时间从大到小排序作业
qsort(jobs, n, sizeof(int), compare);
// 初始化每台机器的当前总处理时间为0
int machines[m];
for (int i = 0; i < m; i++) {
machines[i] = 0;
}
// 将作业分配给机器
for (int i = 0; i < n; i++) {
// 找到当前处理时间最短的机器
int minIndex = 0;
for (int j = 1; j < m; j++) {
if (machines[j] < machines[minIndex]) {
minIndex = j;
}
}
// 分配作业给当前处理时间最短的机器,并更新其总处理时间
machines[minIndex] += jobs[i];
}
// 找到所有机器中总处理时间最长的时间
int maxTime = machines[0];
for (int i = 1; i < m; i++) {
if (machines[i] > maxTime) {
maxTime = machines[i];
}
}
return maxTime;
}
int main() {
int n, m;
scanf("%d %d", &n, &m);
int jobs[n];
for (int i = 0; i < n; i++) {
scanf("%d", &jobs[i]);
}
// 计算并输出完成任务的最短时间
int shortestTime = shortestCompletionTime(n, m, jobs);
printf("%d", shortestTime);
return 0;
}
运行结果:
10. n个孩子站成一排。输入一个整数数组 ratings 表示每个孩子的评分。你需要按照以下要求,给这些孩子分发苹果:每个孩子至少分配到1个苹果。相邻两个孩子评分更高的孩子会获得更多的苹果。请你给每个孩子分发苹果,计算并返回需要准备的最少苹果数目。
#include <stdio.h>
int minApples(int ratings[], int n) {
if (n <= 0) return 0;
int apples[n];
for (int i = 0; i < n; ++i) apples[i] = 1; // 每个孩子至少分配一个苹果
// 从左向右扫描,保证右边评分高的孩子拿到的苹果比左边多
for (int i = 1; i < n; ++i) {
if (ratings[i] > ratings[i - 1]) {
apples[i] = apples[i - 1] + 1;
}
}
// 从右向左扫描,保证左边评分高的孩子拿到的苹果比右边多
for (int i = n - 2; i >= 0; --i) {
if (ratings[i] > ratings[i + 1] && apples[i] <= apples[i + 1]) {
apples[i] = apples[i + 1] + 1;
}
}
int totalApples = 0;
for (int i = 0; i < n; ++i) {
totalApples += apples[i];
}
return totalApples;
}
int main() {
int n;
scanf("%d", &n);
int ratings[n];
for (int i = 0; i < n; ++i) {
scanf("%d", &ratings[i]);
}
int minTotalApples = minApples(ratings, n);
printf("%d", minTotalApples);
return 0;
}
运行结果:
结语
宝剑锋从磨砺出
梅花香自苦寒来
!!!