LeetCode之旅(C):258. 各位相加

PS:不明之处,请君留言,以期共同进步!

1. 题目描述

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。

示例:

输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。

2. 思路一

通过使用while循环,将num的每一位上的数字相加,得到一个和值sum,判断sum是否是一位数,如果是,则返回,如果不是,则将sum赋值给num,再通过while循环执行相同的操作,直到得到的和值是一个一位数为止。

C语言实现

int addDigits(int num)
{
	int sum = num;
	while(true)
	{
		if(sum < 10)
		{
			return sum;
		}
		
		num = sum;
		sum = 0;
		while(num)
		{
			sum += num % 10;
			num /= 10;
		} 
	}
}

(1)当num为负整数时,直接返回原值,通过返回值可以知道输入的实参是负整数;
(2)当num为0-9之间的整数时,直接返回,不需要进入内层while循环;
(3)当num为大于9的整数时,需要进入内层while循环,内层while循环的退出条件是num为0,内层while循环退出后再次进入外层while循环,判断sum是否小于10,如果小于10,则返回sum;否则,将sum赋值给num,并且将sum重置为0,再次进入内层while循环,此时相当于对一个新的num进行各个位上的数字相加操作。如此内外循环,直到得到的sum是一个个位数为止。

2. 思路二

我们对思路一进行改进,首先回顾思路一,对于sum而言,它是将num的各个位上的数字相加得到的结果,我们是通过整个内层while循环将num的所有位上的数字逐个拆开再累加到sum上,如果sum是一个个位数,我们直接返回它就好了;否则我们再将sum的各位上的数字拆分后再相加,然后继续做判断。实际上这等效于将num拆分成两部分,即“个位部分a”和“个位以上的部分b”,我们将“个位部分a”与“个位以上的部分b”相加,得到一个新数称为n1,如果n1是一个一位数,我们直接返回它就好了;否则,我们继续将n1拆分成“个位部分a1”和“个位以上的部分b1”,并且再将“个位部分a1”和“个位以上的部分b1”相加,得到一个新数称为n2,我们再对n2执行相同的判断,如此循环,直到得到的新数ni是一个一位数为止。

C语言实现

int addDigits(int num)
{
	int num1 = 0;
	int num2 = 0;

	while (num > 9)
	{
		num1 = num % 10;
		num2 = num / 10;
		num = num1 + num2;
	}

	return num;
}

3. 思路三

找一找规律,我们知道最后得到的结果肯定是 0 ~ 9 之间的某个数,那么能否找到非负整数num与返回值 0 ~ 9 之间的关系呢?我们发现一共可以分3类情况进行讨论:
(1)第一类情况
只有当num为0时,返回值才为0,而其他所有情况的返回值都不可能为0,因为没有一个非0非负整数的各位数相加会等于0的,所以这种情况要特殊对待。
(2)第二类情况
当num除以9余1时,例如1,10,19,28,37,等等,返回值为1;
当num除以9余2是,例如2,11,20,29,38,等等,返回值为2;
……
当num除以9余8时,例如8,17,26,35,44,等等,返回值为8。
以上的所有情况,余数的值与返回值相同。
(3)第三类情况
当num除以9余0时(num非0),例如:9,18,27,36,45,等等,返回值为9。
这类情况,余数为0,而返回值为9,二者不一致,也需要当成特殊情况来对待。
其实,这3类情况也可以分为两大类情况,即余数为0和余数非0。而当余数为0时,又可以将这一大类情况分成两小类情况,即num为0和num非0。

C语言实现(1)

int addDigits(int num)
{
   return 0 == num ? 0 : 0 == num % 9 ? 9 : num % 9;
}

这里使用了嵌套的三目运算符,我们知道三目运算符的优先级很低(仅高于赋值运算符和逗号运算符),并且遵循从右向左的结合律,所以上述算法中的return语句等价于:

return (0 == num) ? 0 : ((0 == num % 9) ? 9 : (num % 9));

这样加上括号就很清晰了。

C语言实现(2)

int addDigits(int num)
{
   return (num && !(num %= 9)) ? 9 : num;
}

C语言实现(3)


int addDigits(int num) 
{
    if(!(num % 9))
    {
        if(0 == num)
            return 0;
        else
            return 9;
    }
    else 
    {
        return num % 9;
    }
}

int addDigits(int num) 
{
    if(num % 9)
        return num % 9;
    else 
    {
        if(0 == num)
            return 0;
        else
            return 9;
    }
}

C语言实现(4)

int addDigits(int num) 
{
    if(num > 9)
    {
        num %= 9;
        if(0 == num)
            return 9;
    }
    return num;
}

写法(1)(2)(3)(4)的思路都是一样的,只是在(4)中把num为0~9时的num直接返回了。


Tips:既然提到三目运算符,不妨多说一些:

“?:”叫做条件运算符,又叫三目运算符,由条件运算符形成的表达式叫做条件表达式。
关于条件表达式:
<表达式1> ? <表达式2> : <表达式3>
其含义是:先求表达式1的值,如果为真,则执行表达式2,并返回表达式2的结果;如果表达式1的值为假,则执行表达式3,并返回表达式3的结果。一个条件表达式绝不会既计算表达式2,又计算表达式3。

以下是对条件运算符的详细说明:

(1) 通常情况下,表达式1是关系表达式或逻辑表达式,用于描述条件表达式中的条件,表达式2和表达式3可以是常量,变量或表达式。
例如:
(x==y)?‘Y’:‘N’
(d=bb-4a*c)>=0?sqrt(d):sqrt(-d)
ch=(ch>=‘A’&&ch<=‘Z’)?(ch+32):ch
以上均为合法的条件表达式。

(2) 条件表达式的执行顺序为:先求解表达式1,若值为非0,表示条件为真,则求解表达式2,此时表达式2的值就作为整个条件表达式的值;若表达式1的值为0,表示条件为假,则求解表达式3,表达式3的值就是整个条件表达式的值。例如:
(a>=0)?a:-a 执行结果是a的绝对值。

(3) 在程序中,把条件表达式的值直接赋予某个变量。
例如:
min=(a

(4) 条件表达式的优先级别仅高于赋值运算符,而低于前面遇到过的所有运算符。
例如:
min=(a x

(5) 条件运算符的结合方向为"自右至左"。
例如:
a ? b : c ? d : e将按a ? b : (c ? d : e)执行。

(6) 条件表达式允许嵌套,即允许条件表达式中的表达式2和表达式3又是一个条件表达式。
例如:
x>0?1:x<0?-1:0
上述条件表达式中,表达式3部分又是一个条件表达式.根据条件表达式的结合性,上述条件表达式等价于:
x>0?1:(x<0?-1:0)
其作用是判断x的符号情况.当x为正数时,该条件表达式的值为1;当x为负数时,该条件表达式的值为-1;当x为0时,该条件表达式的值为0。

(7) 条件表达式不能取代一般的if语句,仅当if语句中内嵌的语句为赋值语句(且两个分支都给同一变量赋值)时才能代替if语句。
例如:

if(a % 2 == 0)
	printf("even/n");
else
	printf("odd/n");

该语句的作用是:若 a 为偶数,输出 even;若 a 为奇数,输出odd。

(8) 表达式1,表达式2,表达式3的类型可以不同.此时条件表达式的值的类型为它们中较高的类型。


4. 思路四

我们设想对思路三进行改进,将3类情况下的返回值写法进行统一,如果可以做到,那将非常完美。我们发现:
(1)第一类情况
当num % 9为0且num为0时,(num -1) % 9为-1,进而(num - 1) % 9 + 1为0,正好返回值也是0。
(2)第二类情况
当num % 9为0且num非0时,(num - 1) % 9为8,进而(num - 1) % 9 + 1为9,正好返回值也是9。
(3)第三类情况
当num % 9为1时,(num - 1) % 9为0,进而(num - 1) % 9 + 1为1,正好返回值也是1;
当num % 9为2时,(num - 1) % 9为1,进而(num - 1) % 9 + 1为2,正好返回值也是2;
……
当num % 9为8时,(num - 1) % 9为7,进而(num - 1) % 9 + 1为8,正好返回值也是8。
通过以上的分析,我们真的得到了一个统一的公式:返回值 = (num - 1) % 9 + 1,所以最简单的算法如下:

int addDigits(int num) 
{
    return (num - 1) % 9 + 1;
}

以上几种思路,一种比一种简单,活学活用吧。

你可能感兴趣的:(LeetCode之旅)