【20190422】【每天一道算法题】寻找比目标字母大的最小字母(堆)

本文探讨了在特定场景下,如何对二分查找算法进行优化以提高效率,同时揭示了在实现过程中容易忽视的细节问题,如边界条件处理不当可能导致的死循环或错误结果。通过具体的代码实例,对比了不同实现方式的优劣,强调了正确性和效率并重的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

给定一个只包含小写字母的有序数组letters 和一个目标字母 target,寻找有序数组里面比目标字母大的最小字母。

数组里字母的顺序是循环的。举个例子,如果目标字母target = 'z' 并且有序数组为 letters = ['a', 'b'],则答案返回 'a'

示例:

输入:letters = ["c", "f", "j"],target = "a"

输出:"c"

输入:letters = ["c", "f", "j"],target = "c"

输出:"f"

输入:letters = ["c", "f", "j"],target = "d"

输出:"f"

输入:letters = ["c", "f", "j"],target = "g"

输出:"j"

输入:letters = ["c", "f", "j"],target = "j"

输出:"c"

输入:letters = ["c", "f", "j"],target = "k"

输出:"c"

注:

  1. 1. letters长度范围在[2,10000]区间内。

  2. 2. letters 仅由小写字母组成,最少包含两个不同的字母。

  3. 3. 目标字母target 是一个小写字母。


思路及代码:

#include<stdio.h>
#include<stdlib.h>

char nextGreatestLetter(char* letters, int lettersSize, char target);

void main(void){
	char result;
	char letters[4] = {"cfj"};
	int lettersSize = 3;
	char target = 'c';
	result = nextGreatestLetter(letters, lettersSize, target);
	printf("%c\n", result);

	system("pause");
}

////二分查找(做错啦,查找了相同字符的下一个字符)
//char nextGreatestLetter(char* letters, int lettersSize, char target){
//	//char result = '0';
//	int low = 0;
//	int high = lettersSize - 1;
//	int mid = 0;
//	//while(mid != lettersSize-2){  //结束判断条件选的不好,如果是letters=cfg,target=c,那么循环没有执行。
//	//while(result = '0'){   //结束判断条件选的不好,如果是letters=abc,target=c,那么就陷入了死循环。
//	while(low <= high){     //如果这样选结束判断条件,那么low=mid+1,high=mid-1,不然死循环。
//		mid = (low + high) / 2;
//		if(letters[mid] < target)
//			low = mid + 1;
//		else if(letters[mid] > target)
//			high = mid - 1;
//		else{
//			if(mid < lettersSize-1) return letters[mid+1];
//			else return letters[0];
//		}
//	}
//	return letters[0];
//}

//二分查找(更快)
char nextGreatestLetter(char* letters, int lettersSize, char target){
	int low = 1;  //low要从1开始,不然后面的[mid-1]下表索引会溢出。
	int high = lettersSize - 1;
	int mid;
	while(low <= high){
		mid = (low + high) / 2;
        if(letters[mid-1] <= target && letters[mid] > target) 
			return letters[mid];
		else if(letters[mid-1] > target) 
			high = mid - 1;
		else 
			low = mid + 1;
	}
	return letters[0];
}

////遍历字符数组(一次遍历)
//char nextGreatestLetter(char* letters, int lettersSize, char target) {
//	char result;
//	int i = 0;
//	while(i<lettersSize){
//		switch(letters[i++] > target){
//			case 1:
//				result = letters[--i];  //这里需注意,因为上一步switch判断之后做了加一操作,所以这里索引要减一,并且是先减再输出。
//				return result;
//			case 0:
//				break;
//			}
//		}
//	result = letters[0];
//	return result;
//}

知识点:

1. 程序报错:error: control reaches end of non-void function

    原因:可能某个(些)函数本该有返回值,但结果可能无返回值。通常出现在判断语句(如if-else, switch-case等)、循环语句(for, while等)之后,判断和循环之后一定要记得考虑一下最后是否需要返回值,因为可能程序一进来就不符合判断/循环条件!

2. switch-case语句用法:(参考:switch-case用法(值匹配、范围匹配)

switch(值或表达式){
    case 值1:
        操作1;
        break;  //不写break会穿透到下一个break
    case 值2:
        操作2;
        break;
    case 值3:
        操作3;
        break;
    ……
    default:
        如果表达式的值和以上的case后面的值都没有匹配上,那么就执行这里的代码。
        break;
}

//在执行switch-case结构的时候遇到了break,就会结束这个switch-case。
//break是可以省略的,如果省略了break,就会往下一个case项穿透,直到遇到break或者这个switch-case结束为止。
//default是可以省略的,不会有语法错误。如果switch后面的表达式有可能出现的值都在case项里面被罗列出来了,那么就永远不可能执行default,此时就可以省略default。(反正我不建议省略)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Satisfying

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值