LeetCode百日筑基系列主要是为了练习基础的数据结构与算法,题库全为LeetCode简单题(后面会在其他系列更新中等题和困难题),主要使用C语言和Java编写,前期的题目以完成功能为目的,后续会使用更优的算法以及优化代码块。
9.回文数
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
例如,121 是回文,而 123 不是。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/palindrome-number
C语言:
bool isPalindrome(int x){
unsigned int i = 0,j = x;
if(x < 0){
return false;
}
while (x != 0){
i = i * 10 + x % 10;
x = x / 10;
}
return i == j;
}
主体思路:首先负数一定不是回文数,-121首位为-,不可能与1相等。设置一个变量i存储最后的回文数,设置一个变量j存储最初的输入x。由于i*10的过程中可能超出int的范围,所以可以用unsigned(回文不为负)或long类型。
进行数字反转:对于数字 12321,如果执行 12321 % 10,将得到最后一位数字 1,再除以 10 把最后一位数字从 12321 中移除,12321 / 10 = 1232,再求出上一步结果除以 10 的余数,1232 % 10 = 2,就可以得到倒数第二位数字。如果我们把最后一位数字乘以 10,再加上倒数第二位数字,1 * 10 + 2 = 12,就得到了我们想要的反转后的数字。
最后将得到的反转后的数字与最初输入数字比较。
Java:
class Solution {
public boolean isPalindrome(int x) {
if(x < 0 || (x % 10 == 0 && x != 0)){
return false;
}
int i = 0;
while(x > i){
i = i * 10 + x % 10;
x /= 10;
}
return x == i || x == i / 10;
}
}
新思路:在上述数字反转基础上加以优化,当 x < 0 时,x 不是回文数。同样的,如果数字的最后一位是 0,它也不是回文数,如10 数字反转后为01。当然0除外。
上面C的代码将所有数字都反转,但回文数前半部分数字和后半部分的反转数字应是相同的,所以只需反转一半数字即可。
反转一半数字:
奇数个数字如12321,反转三位才过半,i为123,x为12(奇数个数字中间的数不影响判断是否回文)
偶数个数字如1221,反转两位就过半,此时i为12,x为12
所以当x<=i即可停止反转下一位数字。
最后输出时,奇数个数字,判断i/10==x, 偶数个数字判断i == x。
由于判断时前面的成立即可立即输出结果,建议使用||短路运算。
复杂度分析
时间复杂度:O(log n),对于每次迭代,我们会将输入除以 10,因此时间复杂度为 O(\log n)。
空间复杂度:O(1)。我们只需要常数空间存放若干变量。
13.罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/roman-to-integer
C语言
int romanToInt(char * s){
int num = 0;
while(*s){
if(*s == 'V'){
num += 5;
}else if(*s == 'L'){
num += 50;
}else if(*s == 'D'){
num += 500;
}else if(*s == 'M'){
num += 1000;
}else if(*s == 'I'){
num = (*(s+1) == 'X' || *(s+1) == 'V') ? (num - 1) : (num + 1);
} else if(*s == 'X'){
num = (*(s+1) == 'L' || *(s+1) == 'C') ? (num - 10) : (num + 10);
}else if (*s == 'C'){
num = (*(s+1) == 'D' || *(s+1) == 'M') ? (num - 100) : (num + 100);
}
s++;
}
return num;
}
当小值在大值的左边,则减小值,如 IV=5-1=4;当小值在大值的右边,则加小值,如 VI=5+1=6;
Java
class Solution {
public int romanToInt(String s) {
int sum = 0;
int leftNum = getNum(s.charAt(0)); //左边第一位数
for(int i = 1; i < s.length(); i++){ // 循环s里的所有数
int num = getNum(s.charAt(i)); //找到右边下一位的值
if(leftNum < num){ //若左边的值小于右边的值,减去左边的数
sum = sum - leftNum;
}else{ //若左边的值大于或等于右边的值,加上左边的值
sum = sum + leftNum;
}
leftNum = num; //将最后一个数通过leftNum传出
}
return sum = sum + leftNum;
}
public int getNum(char ch){
switch(ch){
case'I' : return 1;
case'V' : return 5;
case'X' : return 10;
case'L' : return 50;
case'C' : return 100;
case'D' : return 500;
case'M' : return 1000;
default : return 0;
}
}
}
java.lang.String.charAt() 方法返回指定索引处的char值。索引范围是从0到length() - 1。对于数组索引,序列的第一个char值是在索引为0
例如:str.charAt(0)检索str中的第一个字符,str.charAt(str.length()-1)检索最后一个字符