目录
零、流程控制
说到循环,就不得不提到一个词——流程控制。
顾名思义,就是根据不同的情况,来分别控制流程的走向,或者说重复执行某个流程。而后者,就是循环。下面列举几个我之前总结下来的几个流程:
1. if - else if - else
这个就比较好理解了,符合哪个条件就执行哪一行的代码。if可以单独使用,但是else if 和 else 不能单独使用。流程的大体结构如下所示:
if (条件表达式1){
代码1;
} else if (条件表达式2){
代码2;
} else {
代码3;
}
2. switch
执行中一个case成立,从这个case向后穿透执行所有case,包括default直到结束,或者遇到break中断跳出switch。
-
例子1:
public static void main(String[] args) { System.out.println("输入:"); int i = new Scanner(System.in).nextInt(); System.out.println("输出:"); switch (i){ case 1: System.out.print(1 + " "); case 2: System.out.print(2 + " "); default: System.out.print(3 + " "); } }
输入:
1
输出:
1 2 3 -
例子2:(加入 break)
public static void main(String[] args) { System.out.println("输入:"); int i = new Scanner(System.in).nextInt(); System.out.println("输出:"); switch (i){ case 1: System.out.print(1 + " "); case 2: System.out.print(2 + " "); break; default: System.out.print(3 + " "); } }
输入:
1
输出:
1 2
3. 循环
循环有三种:for、while、do-while,这几种循环理论上来说是可以相互转换的。
3.1 循环的种类
- for
执行顺序如下所示:① → ② → ③ → ④ → ② → ③ → ④ ……直到不符合执行条件,终止循环。
一般明确循环次数时,使用for循环。
for(①变量赋值;②执行条件;④变量修改){
③代码;
}
- while
当符合判断条件,则进入循环执行代码,执行完继续判断条件表达式,循环执行知道不符合条件,终止循环。
while循环的特点:先判断后执行,有可能一次都不执行。
while (条件表达式){
代码;
}
- do-while
先执行一次代码,再判断条件表达式的值,后面的执行流程就跟while循环一样了。
do-while循环的特点:先执行后判断,至少会执行一次代码。
do {
代码;
} while (条件表达式);
3.2 循环的终止
- break
中断跳出switch或当前循环,这里的跳出当前循环是指终止执行循环 - continue
结束本轮循环,直接开始执行下一轮循环
3.3 循环的命名
//循环1
for (int i = 1;i < 10;i++){
//循环2
for (int j = 10;j > 0;j--){
if (j == 5){
break;
}
}
}
Q:就像上面的代码,循环1中嵌套循环2,,但是我希望当
j
=
5
j = 5
j=5 时,跳出的不是循环2,而是外部的循环1,怎么办?
A:这时候就可以对循环进行命名,然后需要跳出循环时,指定要跳出的是哪个循环,当然,continue也适用。因此上面的代码可以改写成:
//循环1
//outer可以命名为其他名字,只是习惯上最外层循环命名为outer而已
outer:
for (int i = 1;i < 10;i++){
//循环2
for (int j = 10;j > 0;j--){
if (j == 5){
break outer;
}
}
}
一、剑指 Offer 64. 求1+2+…+n
1.题目
求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
限制:
1 <= n <= 10000
2.分析
等差数列求和公式: ( 首 项 + 末 项 ) ∗ 项 数 / 2 (首项+末项)*项数/2 (首项+末项)∗项数/2
3.代码
class Solution {
public int sumNums(int n) {
return (1+n)*n/2;
}
}
二、231. 2 的幂
1.题目
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。
提示:
-231 <= n <= 231 - 1
2.分析
首先观察几个2的幂次的二进制数:
十进制 | 二进制 |
---|---|
1 | 0001 |
2 | 0010 |
4 | 0100 |
8 | 1000 |
可以看出,2的幂次在二进制数表示中,有且只有一位是1,其余都是0。
以 8 为例,如果把该数减 1,7 的二进制数为 0111,那么就会发现:
8 & 7 = 0,二进制运算为:
1000
0111
0000
\begin{array}{r} 1000\\ 0 1 11\\ \hline 0000 \end{array}
100001110000
利用这个特点,就可以转成代码
3.代码
class Solution {
public boolean isPowerOfTwo(int n) {
//转成long类型,防止int类型的最小值-2147483648减1时溢出
long num = n;
//对0进行特殊判断,因为0 & -1 = 0,但0不是2的幂
return num != 0 && (num & (num - 1)) == 0;
}
}
三、3的幂
1.题目
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x
提示:
-231 <= n <= 231 - 1
2.分析
3 x = n 3^x = n 3x=n,求 x x x,可以通过对数换底公式求出。
- 对数换底公式:(对数公式中,n一定大于0)
x = l o g 3 n = l o g 10 n l o g 10 3 x=log_3n=\frac{log_{10}n}{log_{10}3} x=log3n=log103log10n - 浮点数的比较:
-
在浮点数(float、double)的运算中,会出现浮点数运算不精确的问题。
例如:public static void main(String[] args) { System.out.println(1-0.9); }
结果:
0.09999999999999998
又因为 M a t h . p o w ( 3 , i ) Math.pow(3, i) Math.pow(3,i) 方法的返回值是double类型,所以在跟n的比较时,需要用浮点数的比较方式:
a − b < 某 个 精 度 ( 通 常 用 1 e − 6 到 1 e − 10 , 经 验 值 ) a-b<某个精度(通常用1e-6到1e-10,经验值) a−b<某个精度(通常用1e−6到1e−10,经验值)
3.代码
class Solution {
public boolean isPowerOfThree(int n) {
int i = (int) (Math.log10(n) / Math.log10(3));
return n > 0 && Math.abs(Math.pow(3, i) - n) < 1e-10;
}
}
四、342. 4的幂
1.题目
给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x
提示:
-231 <= n <= 231 - 1
2.分析
思路跟第三题一样,主要涉及对数换底公式以及浮点数的判断。
3.代码
class Solution {
public boolean isPowerOfFour(int n) {
int i = (int) (Math.log10(n) / Math.log10(4));
return n > 0 && Math.abs(Math.pow(4, i) - n) < 1e-10;
}
}
五、1492. n 的第 k 个因子
1.题目
给你两个正整数 n 和 k 。
如果正整数 i 满足 n % i == 0 ,那么我们就说正整数 i 是整数 n 的因子。
考虑整数 n 的所有因子,将它们 升序排列 。请你返回第 k 个因子。如果 n 的因子数少于 k ,请你返回 -1 。
提示:
1 <= k <= n <= 1000
2.分析
- 题目给出了 n n n 的范围,才1000,直接遍历。
- 定义一个用于计数的变量
c
o
u
n
t
count
count,当
c
o
u
n
t
count
count 计数到与
k
k
k 相等时,说明当前遍历到的
i
i
i 就是第
k
k
k
个因子,直接返回。 - 如果循环结束还没有返回,说明 c o u n t < k count < k count<k,则返回 − 1 -1 −1;
3.代码
class Solution {
public int kthFactor(int n, int k) {
int i,count = 0;
for (i = 1;i <= n;i++){
if (n % i == 0){
count++;
}
if (count == k){
return i;
}
}
return -1;
}
}
六、367. 有效的完全平方数
1.题目
给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
提示:
1 <= num <= 231 - 1
2.分析
- 利用二分查找
- 我这里二分查找设计的思路是,将 1 1 1 到 n u m num num 看作是一个数组,那么数组长度就是 n u m num num
- 例如:
n
u
m
=
4
num=4
num=4,判断是不是完全平方数
从 1 1 1 开始就相当于一个数组: [ 1 , 2 , 3 , 4 ] [1,2,3,4] [1,2,3,4]
设定左边指针 l = − 1 l = -1 l=−1,右边指针 r = 4 r=4 r=4,所以 m i d = l + ( r − l ) / 2 = − 1 + ( 4 − ( − 1 ) ) / 2 = 1 mid = l + (r - l) / 2=-1+(4-(-1))/2=1 mid=l+(r−l)/2=−1+(4−(−1))/2=1
对于上面的数组来说,下标为 m i d = 1 mid=1 mid=1 位置的元素是 2 2 2,所以计算平方数时要将 m i d + 1 mid+1 mid+1 - 当 t > n u m t>num t>num,则将右指针 r = m i d r=mid r=mid;当 t < n u m t < num t<num ,则将左指针 l = m i d l=mid l=mid;当 t = n u m t = num t=num,则直接返回 t r u e true true
- 因为在计算 ( m i d + 1 ) ∗ ( m i d + 1 ) (mid + 1) * (mid + 1) (mid+1)∗(mid+1) 时,有可能会溢出,所以方法内部变量用 l o n g long long 类型。
3.代码
class Solution {
public boolean isPerfectSquare(int num) {
long l = -1,r = num;
long mid;
while (r - l > 1){
mid = l + (r - l) / 2;
long t = (mid + 1) * (mid + 1);
if (t > num){
r = mid;
} else if (t < num){
l = mid;
} else {
return true;
}
}
return false;
}
}