【C语言】C语言基础习题详解(牛客网)二分查找逻辑

主页:醋溜马桶圈-CSDN博客

专栏:C语言_醋溜马桶圈的博客-CSDN博客

gitee:mnxcc (mnxcc) - Gitee.com

目录


1.三目运算符的使用

三目运算符,即a>b?a:b类型的,很多时候适当的使用三目运算符可以使得代码更简洁有序,减小代码的复杂程度,接下来的例子就可以很明显的展示三目运算符的作用

1.1 if-else语句

使用if-else语句来编写代码,如下

#include <stdio.h>
int main()
{int x=0;int y;scanf("%d",&x);if(x<0){y=1;printf("%d",y);}else if (x==0) {y=0;printf("%d",y);}else {y=-1;printf("%d",y);}
}

1.2 三目运算符

#include <stdio.h>
int main()
{int x,y;scanf("%d",&x);x>0?(y=-1):(x==0?(y=0):(y=1));printf("%d",y);
}

三条if语句即用一条代码代替了,这也是之前文章中提到的编程思维的体现,作为程序员,写程序不是为了简单的运行成功,而是要条理清晰的写出代码,让每一步的运行都有据可循,这样也能减少代码的出错率

2.求两个正整数的最小公倍数

2.1 题目描述

牛客网中的题目描述是这样的

题目链接:求最小公倍数__牛客网

2.2 题目分析

假设两个正整数a,b;

  • 最小公倍数,最小也是这两个数中的较大的一个 

思路

我们可以定义一个变量,变量从这个较大的值开始,看能不能整除这两个数,如果不行,那就+1继续判断,如果不行就继续+1判断,直到可以整除这两个数,则返回最后这个数

2.3 代码(头脑风暴)

2.3.1 代码1

#include <stdio.h>int main() {long a=0;long b=0;scanf("%ld %ld",&a,&b);long max=a>b?a:b;while(max%a!=0||max%b!=0){max++;}printf("%ld",max);return 0;
}

顺着这样的逻辑,我们可以写出这样的代码,看似没有问题,但是当遇到非常大的数字的时候,这个算法就显得很复杂,并不能在规定时间内运行,就像这样

究其原因,是因为我们一个一个试数字,这样的方法其实是最耗费时间的;

那有没有更快的算法呢?答案是肯定

2.3.2 代码2

我们假设存在一个数字m,同时能整除a和b;假设m/a=i,m/b=j;

i的取值肯定是从1开始的,假设我们得到一个i值,这个i*a能整除b,那就说明i*a就是最小公倍数

我们发现,在代码1的逻辑中,我们求最小公倍数用了10次循环; 在这个算法中,我们只用了5次循环便找出了最小公倍数,速度提升了很多

那么我们就顺着这个逻辑写我们的代码2

#include <stdio.h>
int main() {long a=0;long b=0;scanf("%ld %ld",&a,&b);long i=1;while(1){if((i*a)%b==0){break;}i++;}printf("%ld",i*a);return 0;
}

这个时候我们发现,代码顺利通过了

可见我们这个逻辑是行得通的,至此,我们的最小公倍数问题就求解成功了 

2.3.3 思考:为什么要用long?

我们发现,题目的输入描述范围是1-100000

而int的表示范围有限,我们通过实践发现,用int型并不能很好的实现

3.倒置字符串

3.1 题目描述

题目链接:倒置字符串__牛客网 

3.2 题目分析

思考一下,我们可以分为两步

  • 第一步,将整个字符串逆序
  • 第二步,把逆序后的每个单词再逆序

或者我们可以:

  • 第一步,逆序每个单词
  • 第二步,再逆序整个字符串

  • 逆序字符串,需要告诉字符串的起始位置和结束位置
  • 逆序单词,同样需要告诉单词的起始位置和结束位置

这两种算法思维都是可以的,那我们实践一下

3.3 代码

我们可以封装一个reverse函数来进行字符串逆序

实现逻辑是这样的

3.3.1 reverse函数

void reverse(char* left,char* right){while (left<right) {char tmp=*left;*left=*right;*right=tmp;left++;right--;}
}

逆序整个字符串,调用这个函数,逆序单词同样可以调用这个函数

用while循环,当开始指针遇到空格或者'\0'的时候就停止;没有遇到空格或者'\0'的时候,则是一个单词,逆序这个单词

可以看主函数的代码理解 

3.3.2 主函数

#include <stdio.h>
void reverse(char* left,char* right){while (left<right) {char tmp=*left;*left=*right;*right=tmp;left++;right--;}
}
int main() {char arr[101]={0};gets(arr);//逆序整个字符串int len=strlen(arr);reverse(arr,arr+len-1);//逆序每个单词char* cur=arr;while(*cur){char* strat=cur;while (*cur!=' '&&*cur!='\0') {cur++;}char* end=cur-1;reverse(strat, end);if(*cur==' ')cur++;}printf("%s\n",arr);return 0;
}

这样,我们这个问题就解决了

3.3.3 为什么使用gets()接收字符串呢?

因为scanf()接收字符串,遇到空格就停止不会继续往后读取了

4.二维数组中的查找

二维数组中的查找,这是剑指offer中的一道数组方面的题目

牛客网中也有同样的题目

4.1 题目描述

4.2 题目分析

我们在把这个二维数组用图表示出来


4.2.1 二维数组中数字7的查找

由题目可知,每一行的数字是从左向右增大的,每一列的数字是从上到下增大的,即

首先,我们选取数组右上角的数字9,由于9大于7,并且9是第四列第一个(也是最小的)数字,因此7不可能出现在数字9所在的列。于是,我们把这一列从需要考虑的区域内剔除,之后只需要分析剩下的3列。

在剩下的矩阵中,位于右上角的数字是8,同样8大于7,因此8所在的列我们也可以剔除。接下来我们只要分析剩下的两列即可。

在剩余两列组成的数组中,数字2位于数组的右上角。2小于7,那么要查找的7就可能出现在2的右边和下边,而在前两步中,我们已经排除了2右边的列,也就是说7不可能出现在2的右边,只有可能出现在7的下边。于是我们把2所在的行也剔除,只分析剩下的三行两列数字。

在剩下的数字中,数字4位于右上角,和前面一样,我们把数字4所在的行也剔除,最后只剩下两行两列数字。

在剩下的两行两列中,位于右上角的数字刚好就是我们要查找的数字7,于是查找过程结束。

用下图表示

4.2.2 二维数组中数字的查找规律

首先选取数组中右上角的数字。如果该数字等于要查找的数字,则查找过程结束;

如果该数字大于要查找的数字,则剔除这个数字所在的列;如果该数字小于要查找的数字,则剔除这个数字所在的行。

也就是说,如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围中剔除一行或者一列,这样每一步都可以缩小查找的范围,直到找到要查找的数字,或者查找范围为空。

4.3 代码示例

把整个查找过程分析清楚之后,我们再写代码就不是一件很难的事情了。

下面是关于该思路的代码:

bool Find(int target, int** array, int arrayRowLen, int* arrayColLen) {int iRow = 0;int iCol = 0;char bIsFind = false;if (NULL == array) return false;iRow = 0;iCol = *arrayColLen - 1;while (iCol >= 0 && iRow < arrayRowLen) {if (target == array[iRow][iCol]) {bIsFind = true;break;}else if (target <= array[iRow][iCol]) {iCol--;}else {iRow++;}}return bIsFind;
}

5.数字在升序数组中出现的次数 

这道题可以用遍历数组二分查找来处理

5.1 题目描述

5.2 题目分析

题目中有一个关键信息,非降序数组,我们可以使用if语句来处理这个问题

if(numsLen==0){return 0;}
else if (nums[numsLen-1]<k||nums[0]>k) {return 0;}

5.2.1 遍历数组方法

int GetNumberOfK(int* nums, int numsLen, int k ) {int count = 0;if(numsLen==0){return 0;}else if (nums[numsLen-1]<k||nums[0]>k) {return 0;}for(int i=0;i<numsLen;i++){if (k==nums[i]) {count++;}}return count;
}

遍历数组的方法应该是最直接有效的,当k出现一次,则count自增,最终返回count的值即是k出现的次数

5.2.2 二分查找方法

二分查找是我们经常使用的一种算法,他的逻辑是

升序或者降序无重复元素的数组中,比较目标值和数组中间值的方法,每次缩小一半的搜索范围,相比遍历可以加快计算的速度

假设:目标值为下标为4的数值,给定一个大小为10的数组,我们给定他的下界left=0,上界right=numsLen-1,中间下标mid=(left+right)/2

二分查找:

  • 判断目标值target是否等于num[mid];
  • 如果相等则返回mid

如果不相等则判断target与num[mid]的大小关系;

  • target>num[mid];则说明目标值在后半部分,因为mid与目标值不相等,那么left就变成mid+1;
  • target<num[mid];则说明目标值在前半部分,因为mid与目标值不相等,那么right就变成mid-1;

每次缩小范围后都需要继续执行上述步骤,我们可以使用一个while循环,当left<right的时候循环,直到找到目标值对应的下标,返回下标;或者没有目标值对应的下标,返回-1;

5.2.3 代码示例

按照这个思路,我们编写一下我们的代码

int position(int* data, int n, double k){int left = 0, right = n-1, mid = 0;while(left <= right){mid = (left + right)/2;if(data[mid] < k)left = mid + 1;else if(data[mid] > k)right = mid - 1;elsereturn mid;}return left;
}

当然,这是二分查找的代码,根据题目要求,我们调用这个函数

int GetNumberOfK(int* nums, int numsLen, int k ){return position(nums,numsLen, k+0.5) - position(nums,numsLen, k-0.5);
}

找到比k小的第一个数作为左边界,找到比k大的第一个数作为右边界,右-左即k的个数

按普通找某个数的位置来找,只是把int 改为double, 找k-0.5和k+0.5

6.BM80 买卖股票的最好时机(一)

6.1 题目描述

题目链接:买卖股票的最好时机(一)_牛客题霸_牛客网 (nowcoder.com)

6.2 题目分析

我们看到这个题目中一个数组表示每一天的股价,那么最大利润怎么算呢,我们用图片来表示

假设这是我们输入的数组

根据题目的意思,我们需要在股价最低的时候买入,在股价最高的时候抛出;但是这有一个问题,我们只能在买入当天以后的股价中找利润最大的,如果没有最大的,那就返回0;我们推理一下

  • 第一天:最小值8 利润:8-8=0

  • 第二天:最小值8 利润:9-8=1

  • 第三天:最小值2 利润:2-2=0

  • 第四天:最小值2 利润:4-2=2

  • 第五天:最小值2 利润:10-2=8

  • 第六天:最小值1 利润:1-1=0

  • ......

  • 依次递推即可知道:最大利润值即为8

6.3 编写代码

根据这个逻辑,写代码的时候我们需要初始化最低股价min,最大效益maxProfit,当前股价price 

  • 当前股价我们需要假设每一天的情况,所以我们用for循环遍历数组实现
  • 最低股价我们假设数组的第一个元素是最低股价,然后与当前股价比较得出最低股价
  • 每一天的最大利润是当前股价减去最低股价
  • 比较每天的最大利润,得出所有最大利润中最大利润返回
  • 没有利润则返回0

我们编写出下面这段代码

int maxProfit(int* prices, int pricesLen ) {// write code hereint min=*prices;int maxProfit=0;//初始化最大利润int price=0;//初始化当前股价for(int k=0;k<pricesLen;k++){price=prices[i];min=min<price?min:price;//求出当前股价之前的最低股价maxProfit=maxProfit<(price-min)?(price-min):maxProfit;}return maxProfit;
}

7.二分查找逻辑

7.1 二分查找

二分查找是我们经常使用的一种算法,他的逻辑是

升序或者降序无重复元素的数组中,比较目标值和数组中间值的方法,每次缩小一半的搜索范围,相比遍历可以加快计算的速度

7.2 查找逻辑

假设:目标值为下标为4的数值,给定一个大小为10的数组,我们给定他的下界left=0,上界right=numsLen-1,中间下标mid=(left+right)/2

判断目标值target是否等于num[mid];

  • 如果相等则返回mid

如果不相等则判断target与num[mid]的大小关系;

  • target>num[mid];则说明目标值在后半部分,因为mid与目标值不相等,那么left就变成mid+1;
  • target<num[mid];则说明目标值在前半部分,因为mid与目标值不相等,那么right就变成mid-1;

每次缩小范围后都需要继续执行上述步骤,我们可以使用一个while循环,当left<right的时候循环,直到找到目标值对应的下标,返回下标;或者没有目标值对应的下标,返回-1;

7.3 题目练习

我们找到一个题目来练习一下

7.3.1 题目描述

牛客网的题目链接: 二分查找-I_牛客题霸_牛客网 (nowcoder.com)

7.3.2 代码示例

根据二分查找的逻辑,我们可以写下代码: 

int search(int* nums, int numsLen, int target ) {if(nums==NULL){return -1;}int left=0;int right=numsLen-1;int mid=(left+right)/2;while (left<=right) {if (nums[mid]>target) {right=mid-1;}else if (nums[mid]<target) {left=mid+1;}elsereturn mid;mid=(left+right)/2;}return -1;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/288164.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vs2010打包QT程序

一、环境 win10 、 VS2010 、 qt5.7.1 将代码在release模式下运行 运行完后会在相应的文件夹下生成exe文件&#xff0c;也会将部分dll文件拷贝到release文件夹中 二、生成可执行文件 2.1 选择“文件”->“新建”->”项目“ 2.2 在打开的对框中选择”其他类型项目…

蓝桥杯学习笔记 单词分析

试题 G: 单词分析 时间限制: 1.0s 内存限制: 512.0MB 本题总分:20 分 [问题描述] 小蓝正在学习一门神奇的语言&#xff0c;这门语言中的单词都是由小写英文字母组成&#xff0c;有些单词很长&#xff0c;远远超过正常英文单词的长度。小蓝学了很长时间也记不住一些单词&#xf…

完全二叉树的层序遍历[天梯赛]

文章目录 题目描述思路 题目描述 输入样例 8 91 71 2 34 10 15 55 18 输出样例 18 34 55 71 2 10 15 91思路 完全二叉树最后一层可以不满&#xff0c;但上面的每一层的节点数都是满的 后序遍历的顺序为"左右根"&#xff0c;我们可以用数组模拟完全二叉树&#xff0c;…

AQS源码分析

前言 AbstractQueuedSynchronizer是抽象同步队列&#xff0c;其是实现同步机器的基础组件&#xff0c;并发包中的锁的底层就是使用AQS实现的。AQS中 维护了一个volatile int state&#xff08;代表共享资源&#xff09;和一个FIFO线程等待队列&#xff08;多线程争用资源被阻塞…

探索国内ip切换App:打破网络限制

在国内网络环境中&#xff0c;有时我们会遇到一些限制或者屏蔽&#xff0c;使得我们无法自由访问一些网站或服务。而国内IP切换App的出现&#xff0c;为解决这些问题提供了非常便捷的方式。这些App可以帮助用户切换IP地址&#xff0c;让用户可以轻松地访问被限制或屏蔽的网站&a…

ForkJoinPool在生产环境中使用遇到的一个问题

1、背景 在我们的项目中有这么一个场景&#xff0c;需要消费kafka中的消息&#xff0c;并生成对应的工单数据。早些时候程序运行的好好的&#xff0c;但是有一天&#xff0c;我们升级了容器的配置&#xff0c;结果导致部分消息无法消费。而消费者的代码是使用CompletableFutur…

STM32学习笔记(7_2)- ADC模数转换器代码

无人问津也好&#xff0c;技不如人也罢&#xff0c;都应静下心来&#xff0c;去做该做的事。 最近在学STM32&#xff0c;所以也开贴记录一下主要内容&#xff0c;省的过目即忘。视频教程为江科大&#xff08;改名江协科技&#xff09;&#xff0c;网站jiangxiekeji.com 本期开…

稀碎从零算法笔记Day28-LeetCode:零钱兑换

前言&#xff1a;鸽了好多天了哈哈哈&#xff0c;虽然C站没更但是LC还是坚持刷的&#xff0c;任重道远啊&#xff01;(可恶的寝室熄灯) 题型&#xff1a;动态规划 链接&#xff1a;322. 零钱兑换 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述…

五五复制模式:电商营销新策略,轻松打造百万用户平台

你是否曾感受到平台发展的瓶颈&#xff0c;渴望找到一种有效的方式&#xff0c;快速吸引用户&#xff0c;推动平台裂变&#xff0c;进而实现百万用户的规模&#xff1f;今天&#xff0c;我要向你介绍一种创新的商业模式——五五复制模式&#xff0c;它或许能为你带来全新的启示…

Chrome 插件各模块之间的消息传递

Chrome 插件各模块之间的消息传递 一、消息传递 1. 消息传递分类 Chrome 插件的 Action、Background 和 content_script 三个模块之间的信息传输插件和插件之间的信息传输网页向插件进行信息传输与原生应用进行消息传递 2. 消息传递 API runtime API runtime.sendMessage(…

Swift知识点(二)

6. 闭包表达式与闭包 闭包表达式&#xff08;Closure Expression&#xff09; 闭包表达式是一种在简短行内就能写完闭包的语法 也就是&#xff0c;闭包表达式&#xff0c;只是一种简洁、快速实现闭包的语法 Swift 的闭包表达式拥有简洁的风格&#xff0c;鼓励在常见场景中实现…

由浅到深认识Java语言(11):封装

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

MySQL中的日历/时间/时间戳

一&#xff0c;日历 MySQL 使用通常所说的 proleptic 阳历。 每个将日历由朱利安改为阳历的国家在改变日历期间都不得不删除至少10天。 为了了解其运作&#xff0c;让我们看看1582年10月&#xff0c;这是由朱利安日历转换为阳历的第一次: 周一 周二 周三 周四 周五 周六…

单臂路由和三层交换机

目录 一.单臂路由 1.单臂路由的工作原理 2.单臂路由的配置 2.1画出拓扑图 2.2配置PC 2.3配置交换机 2.4配置路由器 2.5测试 二.三层交换机 1.三层交换机的概述 2.三层交换机的配置 2.1画出拓扑图 2.2配置PC 2.3配置二层交换机 2.4配置三层交换机 2.5测试 3.拓展 三.总结 一.…

git提交和回退

目录 一. git 提交二. git commit 后准备回退&#xff0c;尚未 git push三. git add 添加多余文件 撤销操作四. 更改 Git commit 的默认编辑器五. 撤销某个commit的变更六. 回退到之前的commit状态总结&#xff1a; 一. git 提交 git pull # 更新代码 git status # 查看代码状…

ITES | 深圳工业展正运动重磅产品即将亮相

■展会名称&#xff1a; 第二十五届深圳国际工业制造技术及设备展览会&#xff08;以下简称“深圳工业展”&#xff09; ■展会日期 2024年3月28日-31日 ■展馆地点 中国深圳国际会展中心(宝安) ■展位号 9号馆F04 2024年深圳工业展(ITES)将于3月28日至31日在深圳宝安国…

springboot多模块

一、demo 1、创建父项目 首先使用 Spring Initializr 来快速创建好一个Maven工程。然后删除无关的文件&#xff0c;只需保留pom.xml 文件。 &#xff08;1&#xff09;new Project -> spring initializr快速构建SpringBoot&#xff0c;artifactId为springbootmodules&…

SpringBoot+ElasticSearch实现文档内容抽取、高亮分词、全文检索

需求 产品希望我们这边能够实现用户上传PDF、WORD、TXT之内得文本内容&#xff0c;然后用户可以根据附件名称或文件内容模糊查询文件信息&#xff0c;并可以在线查看文件内容。 一、环境 项目开发环境&#xff1a; 后台管理系统springbootmybatis_plusmysqles 搜索引擎&#…

PTA L2-037 包装机

一种自动包装机的结构如图 1 所示。首先机器中有 N 条轨道&#xff0c;放置了一些物品。轨道下面有一个筐。当某条轨道的按钮被按下时&#xff0c;活塞向左推动&#xff0c;将轨道尽头的一件物品推落筐中。当 0 号按钮被按下时&#xff0c;机械手将抓取筐顶部的一件物品&#x…

JVM第八讲:GC - Java 垃圾回收基础知识

GC - Java 垃圾回收基础知识 本文是JVM第八讲&#xff0c; Java 垃圾回收基础知识。垃圾收集主要是针对堆和方法区进行&#xff1b;程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的&#xff0c;只存在于线程的生命周期内&#xff0c;线程结束之后也会消失&#xff0…