三整数排序问题的解题逻辑

news2024/11/17 16:16:38

【题目描述】

输入3个整数,从小到大排序后输出。

【样例输入】

20 7 33

【样例输出】

7 20 33

【解析】

本题解法大概有3种:

1、穷举条件法。

此方法先判断a、b、c大小的所有可能,再根据各种可能性输出不同的排序。

思路是先判断a、b的大小,此时可把a、b想象成一个数轴上的两个点,即将数轴分成3个部分,然后再判断c在这3个部分中的哪一段,由此实现排序输出。

这种方法是正向法,对条件的穷举比较费脑细胞,不够简单明了。

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);

    if(a<b){

        if(c<a){

            printf("%d %d %d", c, a, b);

        }

        else if(c>b){

            printf("%d %d %d",a, b, c);

        }

        else{

            printf("%d %d %d",a, c, b);

        }

    }

    else{

        if(c<b){

            printf("%d %d %d", c, b, a);

        }

        else if(c>a){

            printf("%d %d %d",b, a, c);

        }

        else{

            printf("%d %d %d",b, c, a);

        }

    }

    return 0;

}

2、排列法(最简单的方法)

这种方法属于逆向思维法,其好处是由结果反推条件,能够避开复杂的逻辑判断。

abc三个数的全排列有6种:abc、acb、bac、bca、cab、cba,所以最简单的方法就是直接用if判断这6种输出对应的条件。

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);

    if(a < b && b < c)printf("%d %d %d\n", a, b, c);

    if(a < c && c < b)printf("%d %d %d\n", a, c, b);

    if(b < a && a < c)printf("%d %d %d\n", b, a, c);

    if(b < c && c < a)printf("%d %d %d\n", b, c, a);

    if(c < a && a < b)printf("%d %d %d\n", c, a, b);

    if(c < b && b < a)printf("%d %d %d\n", c, b, a);

    return 0;

}

上述程序看上去没有错误,而且能通过题目中给出的样例,但可惜有缺陷:输入“111”将得不到任何输出!

这个例子说明:样例输出正确不代表程序正确。因为程序要满足对任意符合要求的输入均得到正确的结果,而不仅是样例数据。

上面的问题在于,忽略了输入数据相等的情况。上述6种排列的充分必要条件为:a≤b≤c、a≤c≤b、b≤a≤c、b≤c≤a、c≤a≤b、c≤b≤a。

那把所有的 “<”改成“<=”总可以了吧?很遗憾,还是不行。对于“111”,6种情况全部符合,程序会输出6次“111”。

解决方案是把所有的if改成else if,这样就可以让程序自动排除交叉情况。下面是优化后的最终代码:

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);

    if(a <= b && b <= c) printf("%d %d %d\n", a, b, c);

    else if(a <= c && c <= b) printf("%d %d %d\n", a, c, b);

    else if(b <= a && a <= c) printf("%d %d %d\n", b, a, c);

    else if(b <= c && c <= a) printf("%d %d %d\n", b, c, a);

    else if(c <= a && a <= b) printf("%d %d %d\n", c, a, b);

    else if(c <= b && b <= a) printf("%d %d %d\n", c, b, a);

    return 0;

}

注:最后一条else if还可以简化成单独的else。

英语单词else表示“其他”,也就是“除此之外”、“否则”。比如一个妹子说:if(你爱我) 我就给你生儿子; else 我就死在你面前;

可见,起到排除交叉作用的正是这个else。

有些人称else if为语句,这是错误的,它们并不共同构成一个独立的语句。因else if虽然写在一起,但它们的关系并没有想象中的那么亲密无间。上面的代码本质上只是一个if…else语句的嵌套。

比如,下面这样一组语句:

if(...) ...;

else if(...) ...;

else if(...) ...;

它的真实面目是这样的:

if(...) ...;

else {

    if(...) ...;

    else {

        if(...) ...;

    }

}

只不过后一种写法有些麻烦,故而把else if凑在一起实现了代码形式上的简洁。

总之,有了else就能让编译器为我们排除条件交叉的情况,从而大大简化逻辑判断。

如果本题只用不含else的if语句,大家就能体会到其逻辑判断有多复杂。

不用else,就要人为设置好所有条件,做到“不重不漏”,这样的条件一共有多少种呢?

如果三整数不相等,那么这道题就简单了,本算法中第一段代码就是正解。

但是如果考虑到等号就比较复杂了,所以本题的关键就是判断输入数据相等的情况。

可以根“相等”的情况将本题的条件分类:

①三个数都不相等;

②有两个数相等;

③三个数都相等。

第①种情况刚才已经讨论过了,第③种情况也很简单(即a=b=c),关键是第②种情况。

第②种情况又可分为三种情形:ab相等、bc相等 、ac相等。

当ab相等时,与c比较又分为两种情形:ab小于c,ab大于c。据此上面三种情形又可细分为6种条件:

a) ab相等时分为两种情形:a=b<c,a=b>c;

b) bc相等时分为两种情形:b=c<a,b=c>a;

c) ac相等时分为两种情形:a=c<b,a=c>b;

综上,本题要判断的条件一共有13种:

①三个数都不相等:6种;

②有两个数相等:6种;

③三个数都相等:1种;

这就是人为判断条件的复杂程度,代码如下:

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);



    //三个数都不相等的6种条件

    if(a < b && b < c)printf("%d %d %d\n", a, b, c);

    if(a < c && c < b)printf("%d %d %d\n", a, c, b);

    if(b < a && a < c)printf("%d %d %d\n", b, a, c);

    if(b < c && c < a)printf("%d %d %d\n", b, c, a);

    if(c < a && a < b)printf("%d %d %d\n", c, a, b);

    if(c < b && b < a)printf("%d %d %d\n", c, b, a);



    //两个数相等的6种条件

    if(a == b && b < c)printf("%d %d %d\n", a, b, c);

    if(a == b && b > c)printf("%d %d %d\n", c, a, b);

    if(b == c && c < a)printf("%d %d %d\n", b, c, a);

    if(b == c && c > a)printf("%d %d %d\n", a, b, c);

    if(a == c && c < b)printf("%d %d %d\n", a, c, b);

    if(a == c && c > b)printf("%d %d %d\n", b, a, c);



    //三个数都相等的1种条件

    if(a == b && b == c)printf("%d %d %d\n", a, b, c);

   

    return 0;

}

这段代码虽然条件很多,但好在理解起来容易。

能不能减少一下判断条件的数量呢,可以的,但是就需要更复杂的逻辑判断,理解起来也更复杂。

思路就是把“两个数相等的6种条件”与“三个数都不相等的6种条件”合并判断,更确切地说是把前者“插入”到后者。

后者表达式中所有的符号都是“<”,所以问题就变成了在后者的表达式中加“=”。

这里面需要注意:合并后的每个条件表达式只能含有一个等号。换句话说,“两个数相等的6种条件”中的每个条件只能与“三个数都不相等的6种条件”中唯一的一个条件合并,6种条件要一一对应。

因为一旦含有两个等号,就会出现重复条件判断。

比如a <= b < c可以分解为:a <b < c,a <=b < c。

而a <= b < =c却会分解为:a <b < c,a <b = c,a=b < c,a=b=c。

如果把要加等号的条件以“&&”为线分为左右两部分,则两侧都不能出现相同的等式,如下图:

总结起来规则有两条:

①每个if条件中只能有一个“=”;

②&&左右两侧都不能出现相同的等式。

假设在第一个条件中的a <b && b < c左侧加入等号,即变成a <=b && b < c,则可以依照上面两条规则从此等号开始按下图路线推出所有要加“=”的地方。

加入“=”后的代码如下:

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);



    //三个数都不相等+两个数相等的6种条件

    if(a <= b && b < c)printf("%d %d %d\n", a, b, c);

    if(a < c && c <= b)printf("%d %d %d\n", a, c, b);

    if(b < a && a <= c)printf("%d %d %d\n", b, a, c);

    if(b <= c && c < a)printf("%d %d %d\n", b, c, a);

    if(c <= a && a < b)printf("%d %d %d\n", c, a, b);

    if(c < b && b <= a)printf("%d %d %d\n", c, b, a);



    //三个数都相等的1种条件

    if(a == b && b == c)printf("%d %d %d\n", a, b, c);

    return 0;

}

前面讲过,a <= b < =c分解为:a <b < c,a <b = c,a=b < c,a=b=c,所以可以将代码进一步合并:

#include<stdio.h>

int main(){

    int a, b, c;

    scanf("%d%d%d", &a, &b, &c);



    //三个数都不相等+两个数相等+三个数都相等的6种条件

    if(a <= b && b <= c)printf("%d %d %d\n", a, b, c);

    if(a < c && c < b)printf("%d %d %d\n", a, c, b);

    if(b < a && a <= c)printf("%d %d %d\n", b, a, c);

    if(b <= c && c < a)printf("%d %d %d\n", b, c, a);

    if(c <= a && a < b)printf("%d %d %d\n", c, a, b);

    if(c < b && b <= a)printf("%d %d %d\n", c, b, a);



    return 0;

}

这就是不含else的最精简的代码。

之所以弄这么一大通,就是为了让客官体验一下没有else的帮助编写代码将会多么的复杂,而且一不小心等号加错了位置就会前功尽弃。有了else就完全避免了以上复杂的逻辑分析,还不容易出错,真的是又快又准。

3、交换变量排序法:还有一种思路是把a、b、c这3个变量本身改成a≤b≤c的形式。步骤如下:

1)通过交换变量让a变成3个数的最小值。首先让a分别与b、c比较,如果a>b、c,则交换a和b、c(利用前面讲过的三变量交换法),从而保证a≤c,且a≤b,也就是将a变成3个数的最小值。

2)通过交换变量让b变成b、c中的最小值。检查b和c,如果b>c,交换b、c。

#include<stdio.h>

int main(){

    int a, b, c, t;

    scanf("%d%d%d", &a, &b, &c);

    if(a > b) { t = a; a = b; b = t; } //执行完毕之后a≤b

    if(a > c) { t = a; a = c; c = t; } //执行完毕之后a≤c,且a≤b依然成立

    if(b > c) { t = b; b = c; c = t; }

    printf("%d %d %d\n", a, b, c);

    return 0;

}

总结:本题需要注意的是输入限定条件——3个整数。也就是说只要满足3个整数即可,没限定这3个整数相不相等。所以,本题要考虑输入的三个数相等的情况。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序开发:循环定时删除阿里云oss上传的文件

上文有说到我们开发了定时删除阿里云oss的功能&#xff0c;但是一次只能删除10条。 本文我们做到一次删除全部过期的文件。 实现&#xff1a;使用while循环&#xff0c;在循环里获取是否还有已过期的&#xff0c;没有就break掉&#xff0c;有就走删除逻辑。 开始代码部分&am…

云原生团队如何实现加量不加价

随着云原生技术的快速发展&#xff0c;越来越多的业务实现了上云&#xff0c;云原生团队在工作量增大的同时也随之变成了所有问题对接的入口&#xff0c;如何承担这个保姆的角色成为了一道难题&#xff0c;故障的定界和问题证据的交接更是让人头疼的问题。在这种情况下需要有工…

2024年租用阿里云服务器多少钱?阿里云服务器租用价格表(最新版)

2024年租用阿里云服务器一年多少钱&#xff1f;不同时期阿里云服务器的租用价格不同&#xff0c;随着2024年阿里云上云采购季活动的开启和阿里云最新一轮的云产品降价调整&#xff0c;阿里云服务器租用价格也做了一些调整&#xff0c;配置最低的1核1G云服务器收费标准为22.8/月…

【中间件】RabbitMQ入门

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;中间件 ⛺️稳中求进&#xff0c;晒太阳 MQ的优劣&#xff1a; 优势 应用解耦&#xff1a;提升了系统容错性和可维护性异步提速&#xff1a;提升用户体验和系统吞吐量消峰填谷&#xff1…

【Spring云原生】Spring官宣,干掉原生JVM,推出 Spring Native!整体提升性能!Native镜像技术在Spring中的应用

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &#x1f680; 本…

c++的队列的用法

基本介绍 c的队列就是std::queue。 需要包含的头文件&#xff1a; #include<queue>queue就是先进先出队列 queue,就是队列&#xff0c;队列是一种容器适配器&#xff0c;专门设计用于在FIFO上下文中操作(先进先出)&#xff0c;其中将元素插入容器的一端并从另一端提…

LangChain 教程:构建 LLM 支持的应用程序的指南

作者&#xff1a;Aditya Tripathi GPT-4 和 LLaMA 等大型语言模型 (LLM) 在过去几年中创造了一个充满可能性的世界。 它预示着人工智能工具和应用程序的繁荣&#xff0c;ChatGPT 似乎一夜之间成为家喻户晓的名字。 但如果没有为促进新一代应用程序而创建的强大工具和框架&#…

【面试题】webpack的五大核心、构建流程、性能优化

【面试题】webpack的五大核心、webpack的构建流程、webpack的性能优化 webpack是什么?webpack的五大核心webpack的构建流程webpack性能优化 webpack是什么? js静态模块打包工具。 功能 将多个文件打包成更小的文件&#xff0c;(压缩)翻译 babal-loader es6进行降级兼容。 …

【pyinstaller打包记录】Linux系统打包可执行文件后,onnxruntime报警告(Init provider bridge failed)

简介 PyInstaller 是一个用于将 Python 程序打包成可执行文件&#xff08;可执行程序&#xff09;的工具。它能够将 Python 代码和其相关的依赖项&#xff08;包括 Python 解释器、依赖的模块、库文件等&#xff09;打包成一个独立的可执行文件&#xff0c;方便在不同环境中运行…

如何根据企业司法涉诉大数据合理规避风险?

在当前的商业环境中&#xff0c;企业司法涉诉的信息越来越成为衡量一家企业信誉和运营风险的重要标准。大数据时代的到来&#xff0c;让我们有了更加丰富的手段对这些信息进行挖掘与分析&#xff0c;从而对企业可能面临的风险进行预警。本文将探讨如何通过对企业司法涉诉的大数…

服务器硬件监控,保障系统稳健运行的关键策略

服务器硬件在运维中扮演着至关重要的角色&#xff0c;超过一半的网络中断是由硬件故障引起的&#xff0c;这使得硬件性能监控成为运维中不可或缺的一部分。对于一个组织或企业的信息技术基础设施而言&#xff0c;重要性不言而喻&#xff1a; 1. 安全性&#xff1a;服务器硬…

虚拟内存地址动静态库

前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第5篇,在这里分享给大家,还有一些书籍《[深入理解计算机系统》《计算机组成&#xff1a;结构化方法》《计算机体系结构&#xff1a;量化研究方法》《程序员的自我修养》&#xff0c;今天我们来了解程序的虚拟…

聚观早报 | 2024款腾势D9将发布;岚图汽车2月销量

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月2日消息 2024款腾势D9将发布 岚图汽车2月销量 苹果Vision Pro防汗新专利 真我12 Pro正式开售 Redmi K70/Pro…

wvp-gb28181-pro国标设备录像下载

点击【国标设备】&#xff0c;进入设备通道 每个通道右边都有对应的操作&#xff0c; 点击操作栏中的【设备录像】按钮 点击【设备录像】进入录像查看页面&#xff0c;选择要查看的日期即可对录像进行播放和下载 播放&#xff1a;双击录像名称 下载&#xff1a;点击下载按钮 下…

SpringBoot实现分页模糊查询

1. Navicat查询数据 Navicat中查询所有数据 SELECT * FROM sys_user;Navicat中查询前两条数据&#xff08;俩种方式&#xff09; SELECT * FROM sys_user LIMIT 2; //从0开始&#xff0c;第一个参数是起始位置即(pageNum-1)*pageSize&#xff0c;第二个参数是步长 SELECT * …

一文搞定Pytorch CUDA Toolkit与Driver的关系

1. 在我们使用Pytorch不同的版本时&#xff0c;有这样一个大致的对应关系&#xff0c;即&#xff1a;Pytorch版本CUDA Toolkit版本NVIDIA Driver 版本。 难点在于CUDA版本与Driver版本的关系&#xff0c;简单通过NVIDIA官网解决&#xff1a;CUDA Compatibility 这里既有关于Li…

JavaScript的`call`方法:实现函数间的调用!

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Golang 程序启动原理详解

一.编译 go源代码首先要通过 go build 编译为可执行文件,然后去机器上直接执行的&#xff0c;在 linux 平台上为 ELF 格式的可执行文件&#xff0c;linux 能直接执行这个文件,而编译阶段会经过编译器、汇编器、链接器三个过程最终生成可执行文件 编译器&#xff1a;*.go 源码通…

基于“xxx” Androidx平台的驱动及系统开发 之 触摸板篇

目录 一、基于全志 A133 Android10平台&#xff0c;适配1366x768 - ilitek2511触摸1、原理图分析2、驱动移植与适配3、补丁和资源文件 二、基于瑞芯微 RK3566 Android11平台&#xff0c;适配GT9XX触摸1、原理图分析2、补丁及资源文件 三、遇到的问题与解决1、基于amlogic Andro…

【Leetcode】1588.所有奇数长度子数组的和

题目描述 思路 题目要求我们求解所有奇数长度数组的和。若暴力循环求解&#xff0c;时间复杂度过高。所以&#xff0c;我们可以采用前缀和优化。 如上图输入arr数组&#xff0c;sum[i]用于计算arr数组中前i个数的和。(在程序中&#xff0c;先给sum[0]赋值&#xff0c;等于arr[0…