3.你所不知道的go语言控制语句——Leetcode习题69

知道,go,语言,控制,语句,leetcode,习题 · 浏览次数 : 120

小编点评

```go package main import ( "fmt" ) func main() { // 获取输入 var x int fmt.Printf("请输入分数(0-5):\n") fmt.Scanf("%d", &x) // 使用二分法计算 x 的平方根 result := mySqrt(x) // 打印结果 fmt.Printf("x 的平方根是:%d\n", result) } // 计算并返回 x 的平方根 func mySqrt(x int) int { // 初始化左右边界 a := 0 b := x // 使用二分法不断调整左右边界 for a <= b { mid := (a + b) / 2 // 如果二分结果等于 x,则返回平方根 if mid * mid == x { return mid } // 如果二分结果小于 x,则更新左边界 else if mid * mid < x { a = mid + 1 } else { b = mid - 1 } } // 如果二分结果大于 x,则说明搜索范围为空 return b } ``` **解释代码:** 1. 首先,获取用户输入的分数,并将其类型转换为 `int`。 2. 使用 `for` 循环使用二分法不断调整左右边界 `a` 和 `b`,并根据二分结果选择搜索范围。 3. 在搜索过程中,使用 `if` 和 `else` 语句根据二分结果更新 `a` 和 `b`。 4. 如果二分结果等于 `x`,则说明搜索范围为空,返回 `b`(因为 `b` 是搜索范围的右边界)。 5. 如果二分结果小于 `x`,则更新 `a` 指标向右移动。 6. 如果二分结果大于 `x`,则说明搜索范围为空,返回 `b`。 7. 最后,如果搜索过程找到符合条件的答案,则将其返回。

正文

本篇前瞻

好的,现在你已经来到一个新的小结,在这里你将学习到go语言的重要内容,习得go 25个关键字中的12个:var, const, if, else, switch, case, default, fallthrough, for, break, goto, continue,即在顺序结构学习var,const,在分支结构中学习if, else, switch, case, default, fallthrough,在循环结构中学习for, break, goto, continue。另外你最好注册一个Leetcode账号.

Leetcode习题9

让我们再来看下这个例子,这个是一个比较好的例子,里面包含了顺序,分支以及循环的所有控制结构

题目描述

9. 回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

代码编写

func isPalindrome(x int) bool {
	if (x < 0) { //分支结构
		return false
	}
	x64 := x   //顺序结构
	px64 := 0
	for x64 != 0 {  //循环结构
		px64 = px64*10 + x64%10 // 顺序结构
		x64 /= 10
	}
	return px64 == x 
}

你在这个道题目中能看到所有的控制结构:顺序结构,分支结构,循环机构

控制结构

顺序结构(Sequence)

声明和赋值

在顺序结构中声明和赋值是很重要的

var可以声明一个变量,而const则声明一个常量

package main

import "fmt"

func main() {
	var i1 int     //声明变量,默认值为0
	var i2 int = 1 //声明变量,初始化为1
	i3 := 2        //这是最常用的声明和初始化手段
	fmt.Println(i1, i2, i3)
	i4 := i2 + i3 //使用运算表达式赋值
	i3 *= i4      //使用运算表达式赋值
	fmt.Println(i3, i4)
	const ci1 int = 13 //声明常量,无法
	fmt.Println(ci1)
	x, y, z := 100, 101, 102 //多返回值
	fmt.Println(x, y, z)     //打印结果
}

输出:

0 1 2
6 3
13
100 101 102

这里仅仅举例了整形int的声明

多返回值赋值

x,y,z := 0,1,2

go语言允许这样多返回值赋值赋值方式,再挖个坑,原因会在介绍函数时说明一下。

运算符

算术运算符

++ --
自增1 自减1
+= -= *= /= %=
自增 自减 自乘 自除 自模,取余
+ - * / %
加法 减法 乘法 除法 模,取余

注意: 例如如3/2 在整型中是整除即3/2=1,在浮点型是3.0/2.0=1.5,模运算智能用于整数

位运算符

<< >> & | ^
左移 右移 亦或
<<= >>= &= |= ^=
自左移 自右移 自与 自或 自亦或

位运算符几乎我们这篇实用的编程用不到,但是这个概念也很重要,计算机底层事实上是这样工作的,这里在挖个坑,后面会介绍位运算的相关leetcode题目,你会看到它的威力。

逻辑运算

&& || == !=
相等 不等于
>= <= > <
大于等于 小于等于 大于 小于

这些会在分支语句中大放异彩。

分支结构

if 语句

if 语句有if,if-else以及if-else if-else结构,如下所示:

package main

import "fmt"

func main() {
	var input int
	fmt.Printf("请输入分数:")
	fmt.Scanf("%d", &input)
	if input < 60 { //if
		fmt.Println("1.不合格")
	}

	if input < 60 { //if-else
		fmt.Println("2.不合格")
	} else{
		fmt.Println("2.合格")
	}

	if input < 60 {//if-else if-else
		fmt.Println("3.不合格")
	} else if input < 70 {
		fmt.Println("3.合格")
	} else if input < 85 {
		fmt.Println("3.良好")
	} else  {
		fmt.Println("3.优秀")
	}
}

结果如下:

请输入分数:59
1.不合格
2.不合格
3.不合格

switch 语句

事实上switch 语句比if语句更为强大,在有多个分支时更为符合go语言的风格,完整代码如下:

package main

import "fmt"

func main() {
	var i int
	fmt.Printf("请输入分数:")
	fmt.Scanf("%d\n", &i)
	switch {
	case i < 60: //单个逻辑表达式
		fmt.Println("不合格")
	case i < 70:
		fmt.Println("合格")
	case i < 85:
		fmt.Println("良好")
	default:
		fmt.Println("优秀")
	}

	var c byte
	fmt.Printf("请输入等级:")
	fmt.Scanf("%c\n", &c)

	switch c {
	case 'E', 'e': //可以有多个选择
		fmt.Println("1.不合格")
	case 'D', 'd':
		fmt.Println("1.基本合格")
	case 'C', 'c':
		fmt.Println("1.合格")
	case 'B', 'b':
		fmt.Println("1.良好")
	case 'A', 'a':
		fmt.Println("1.优秀")
	default:
		fmt.Println("1.错误的输入")
	}

	switch {
	case c == 'E', c == 'e': //可以有多个表达式
		fmt.Println("2.不合格")
	case c == 'D', c == 'd':
		fmt.Println("2.基本合格")
	case c == 'C', c == 'c':
		fmt.Println("2.合格")
	case c == 'B', c == 'b':
		fmt.Println("2.良好")
	case c == 'A', c == 'a':
		fmt.Println("2.优秀")
	default:
		fmt.Println("2.错误的输入")
	}

	switch {
	case c == 'E':
		fmt.Println("3.不合格")
		fallthrough //fallthrough会执行下一个case区块
	case c == 'e':
		fmt.Println("3.真的不合格")
	case c == 'D', c == 'd':
		fmt.Println("3.基本合格")
	case c == 'C', c == 'c':
		fmt.Println("3.合格")
	case c == 'B', c == 'b':
		fmt.Println("3.良好")
	case c == 'A', c == 'a':
		fmt.Println("3.优秀")
	default:
		fmt.Println("3.错误的输入")
	}

	var in interface{} = i
	switch data := in.(type) { //类型推断
	case int:
		fmt.Printf("int: %v\n", data)
	case uint:
		fmt.Printf("uint: %v\n", data)
	default:
		fmt.Printf("type: %T\n", data)
	}
}

结果如下:

请输入分数:90
优秀
请输入等级:E
1.不合格
2.不合格
3.不合格
3.真的不合格
int: 90

逻辑表达式

注意case可以是单个或多个逻辑表达式

	switch {
	case c == 'E', c == 'e': //可以有多个表达式
		fmt.Println("2.不合格")。
	case c == 'D', c == 'd':
		fmt.Println("2.基本合格")
	case c == 'C', c == 'c':
		fmt.Println("2.合格")
	case c == 'B', c == 'b':
		fmt.Println("2.良好")
	case c == 'A', c == 'a':
		fmt.Println("2.优秀")
	default:
		fmt.Println("2.错误的输入")
	}

fallthrough

fallthrough会执行下一个case区块

	switch {
	case c == 'E':
		fmt.Println("3.不合格")
		fallthrough //fallthrough会执行下一个case区块
	case c == 'e':
		fmt.Println("3.真的不合格")
	case c == 'D', c == 'd':
		fmt.Println("3.基本合格")
	case c == 'C', c == 'c':
		fmt.Println("3.合格")
	case c == 'B', c == 'b':
		fmt.Println("3.良好")
	case c == 'A', c == 'a':
		fmt.Println("3.优秀")
	default:
		fmt.Println("3.错误的输入")
	}

类型推断

这个是一个强大的方式,它可以用于推断go语言的接口的类型,不过现在只能简单那介绍一下,你可以将interface{}可以表达任何类型

	var in interface{} = i
	switch data := in.(type) { //类型推断
	case int:
		fmt.Printf("int: %v\n", data)
	case uint:
		fmt.Printf("uint: %v\n", data)
	default:
		fmt.Printf("type: %T\n", data)
	}

循环语句

循环语句只有for

package main

import "fmt"

func main() {
	var input int
	fmt.Printf("请输入分数(0-5):")
	fmt.Scanf("%d", &input)

	for i := 0; i < 5; i++ { //正常的for
		fmt.Println("loop1:", i)

		if i < 2 {
			continue //跳过本次执行
		}
		if i == input {
			fmt.Println("loop1: break") //跳出本层循环
			break
		}
	}
	i := 0
Loop:
	for i < 5 { //去掉;的for循环
		fmt.Println("loop2:", i)
		for j := 0; j < 5; j++ {
			if j == input {
				fmt.Println("loop2: break Loop") //跳出Loop标记的循环
				break Loop
			}
			if j == 1 {
				break //跳出本层循环
			}
		}
		i++
	}
	i = 0
	for ; i < 5; i++ { //空缺一个元素并带有;的for循环
		fmt.Println("loop3:", i)
		for j := 0; j < 5; j++ {
			if j < 2 {
				continue
			}
			if j == input {
				goto Exit //跳出到Exit
			}
		}
	}
	return
Exit:
	fmt.Println("loop3: Exit")
}

结果如下:

请输入分数(0-5):1
loop1: 0
loop1: 1
loop1: 2
loop1: 3
loop1: 4
loop2: 0
loop2: break Loop
loop3: 0
loop3: 1
loop3: 2
loop3: 3
loop3: 4

请输入分数(0-5):2
loop1: 0
loop1: 1
loop1: 2
loop1: break
loop2: 0
loop2: 1
loop2: 2
loop2: 3
loop2: 4
loop3: 0
loop3: Exit

continue

跳过本次循环

break

没有加标签的就是跳过本层循环

加标签的就是跳过被标签标记的循环

goto

跳到被标签标记的循环,使用goto在处理一些同意的错误或者统一的出口而降低代码的冗余,增加代码可读性。这里挖个坑,这里会在go-etl展示goto的魅力

注意:很多书籍指出goto会破环代码结构,降低代码可读性,那是因为这些书籍讲述使用goto的场景错了

Leetcode习题69

我们以leetcode习题开始,而现在有以一道Leetcode习题结束

题目描述

69. x 的平方根

给你一个非负整数 x ,计算并返回 x算术平方根

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5

题目分析

这道题会比Leetcode习题1更加困难些,这次数据范围是int32的非负整数范围,由于不能使用指数函数和算符,为此,在这里我们需要使用二分法,即通过二分[a,b](mid = a + (b-a)/2, 第一轮a=0,b=x)去获取mid=x/2,如果mid*mid<x 那么此时二分[a,mid-1],反之二分[mid+1,b], 这样不断二分下去直到 mid*mid=x或者a<b。好的,这样我们获得了解题思路,但是还有个问题,选择y的数据类型是什么,如果选择int32,那么相乘必然超过int32, 为此我们必须选择int64,注意:在Leetcode习题9中得出了结论,int是64位的,所以不用改为int64

代码编写

func mySqrt(x int) int {
	a, b := 0, x //多返回值赋值
	for a <= b { // 无;结构的for
		mid := a + (b-a)/2   //二分区间
		if mid*mid == x { //if语句
			return mid
		}
		if mid*mid < x { //if-else语句
			a = mid + 1   //选择较大的区间
		} else {
			b = mid - 1  //选择较小的区间
		}
	}
	return b
}

本篇小结

恭喜你已经完成了所有控制结构的学习,你以及知道了所有控制结构用到的保留字和注意点。另外,通过Leetcode习题69和Leetcode习题9,你已经知道在编程时选择数据类型的重要性,并且练习了所有控制结构。这里的相关代码放在go语言学习的go-base/3中,请下载后进行实际的练习

注意:之后的Leetcode题目解答以及使用工具的编程中,数据类型的选择以及控制结构的应用是非常重要的,也是最为基础的

下篇预告

go语言复合类型

与3.你所不知道的go语言控制语句——Leetcode习题69相似的内容:

3.你所不知道的go语言控制语句——Leetcode习题69

[TOC] # 本篇前瞻 好的,现在你已经来到一个新的小结,在这里你将学习到go语言的重要内容,习得go 25个关键字中的12个:var, const, if, else, switch, case, default, fallthrough, for, break, goto, continue,

控制流程知识点总结

第一部分:条件判断 if 条件1: #父级 满足条件1的时候所执行的代码 # 子级 a=90 # 转换成bool类型 print(a==6) # 当满足条件的时候执行当前子级结束以下所有分支语句 记住这句话 if a>80: # 满足条件的情况下才去执行以下代码 声明条件 print('恭喜你,考了

如何在2023年开启React项目

在这里,我想给你一个新的React项目入门的简要概述。我想反思一下优点和缺点,反思一下作为一个开发者所需要的技术水平,反思一下作为一个React开发者,每个启动项目都能为你提供哪些功能。最后,你将了解到针对不同需求的3种解决方案。 **免责声明**:从个人开发者的角度来看,我完全支持React团队在

职场IT老手教你3步教你玩转可视化大屏设计,让领导眼前一亮!

本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 我是制造企业的IT中心的研发人员,平常工作就是配合业务部门出出报表,选型一些商业软件,并在内部负责实施运维。最近领导出去参观了一些数字化转型比较领先的工厂和制造企业,回

职场IT老手教你3步教你玩转可视化大屏设计,让领导眼前一亮!

本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 我是制造企业的IT中心的研发人员,平常工作就是配合业务部门出出报表,选型一些商业软件,并在内部负责实施运维。最近领导出去参观了一些数字化转型比较领先的工厂和制造企业,回

使用shell脚本在Linux中管理Java应用程序

目录前言一、目录结构二、脚本实现1. 脚本内容2. 使用说明2.1 配置脚本2.2 脚本部署2.3 操作你的Java应用总结 前言 在日常开发和运维工作中,管理基于Java的应用程序是一项基础且频繁的任务。本文将通过一个示例脚本,展示如何利用Shell脚本简化这一流程,实现Java应用的一键式启动、

3分钟带你搞定Spring Boot中Schedule

一、背景介绍 在实际的业务开发过程中,我们经常会需要定时任务来帮助我们完成一些工作,例如每天早上 6 点生成销售报表、每晚 23 点清理脏数据等等。 如果你当前使用的是 SpringBoot 来开发项目,那么完成这些任务会非常容易! SpringBoot 默认已经帮我们完成了相关定时任务组件的配置,

带你熟悉3种AQS的线程并发工具的用法

摘要:AQS 的全称为(AbstractQueuedSynchronizer),AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器。 本文分享自华为云社区《【高并发】AQS中的CountDownLatch、Semaphore与CyclicBarrier核

带你认识3个J.U.C组件扩展

摘要:本文主要为大家讲解3种J.U.C组件扩展。 本文分享自华为云社区《【高并发】J.U.C组件扩展》,作者: 冰 河。 1.FutureTask FutureTask是J.U.C(java.util.concurrent)下的,但不是AQS(AbstractQueuedSynchronizer)的

3步带你搞定华为云编译构建CodeArts Build “新手村任务”

本文将给各位开发者带来华为云CodeArts Pipeline的手把手初级教学,让没有接触过的开发者能够轻松上手体验。