LeetCode 6. Z 字形变换 / 564. 寻找最近的回文数 / 258. 各位相加
Posted Zephyr丶J
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 6. Z 字形变换 / 564. 寻找最近的回文数 / 258. 各位相加相关的知识,希望对你有一定的参考价值。
6. Z 字形变换
2022.3.1 每日一题,又是新的一月了
题目描述
将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
示例 1:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
示例 2:
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
解释:
P I N
A L S I G
Y A H R
P I
示例 3:
输入:s = “A”, numRows = 1
输出:“A”
提示:
1 <= s.length <= 1000
s 由英文字母(小写和大写)、’,’ 和 ‘.’ 组成
1 <= numRows <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zigzag-conversion
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
我这里为了用这个方向标记专门这样写的
class Solution
public String convert(String s, int numRows)
/*
//如果有5行,1 9 17
2 8 10 16
3 7 11 15
4 6 12 14
5 13
*/
//所以呢,遍历这个字符串,到了5转弯
if(numRows == 1)
return s;
String[] ss = new String[numRows];
Arrays.fill(ss, "");
int l = s.length();
int idx = 0;
int dir = 1;
for(int i = 0; i < l; i++)
char c = s.charAt(i);
ss[idx] = ss[idx] + c;
if(idx % (2 * (numRows - 1)) == 0)
dir = 1;
else if((idx + numRows - 1) % (2 * (numRows - 1)) == 0)
dir = -1;
idx += dir;
String res = "";
for(String t : ss)
res = res + t;
return res;
最开始写的代码是观察每一行的规律从而直接构造的,
class Solution
public String convert(String s, int numRows)
//感觉像是找规律题一样,找一下规律应该就做出来了
//1 9 17
//2 8 10 16 18
//3 7 11 15 19
//4 6 12 14
//5 13
//5行,所以第一行两个数相差 (5 - 1) * 2 = 8
//第二行,6,2;第三行4,4....
if(numRows == 1)
return s;
int left = (numRows - 1) * 2;
int right = 0;
int l = s.length();
StringBuffer sb = new StringBuffer();
for(int i = 0; i < numRows; i++)
int j = i;
if(j < l)
sb.append(s.charAt(j));
while(j < l)
if(i != numRows - 1)
j += left;
if(j >= l)
break;
sb.append(s.charAt(j));
if(i != 0)
j += right;
if(j >= l)
break;
sb.append(s.charAt(j));
left -= 2;
right += 2;
return sb.toString();
564. 寻找最近的回文数
2022.3.2 每日一题
题目描述
给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。
“最近的”定义为两个整数差的绝对值最小。
示例 1:
输入: n = “123”
输出: “121”
示例 2:
输入: n = “1”
输出: “0”
解释: 0 和 2是最近的回文,但我们返回最小的,也就是 0。
提示:
1 <= n.length <= 18
n 只由数字组成
n 不含前导 0
n 代表在 [1, 10^18 - 1] 范围内的整数
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-the-closest-palindrome
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
硬生生考虑了所有情况
提交之前没考虑100 1000 这种情况,加上以后竟然过了,还超过了百分之九十多
首先一般情况就是直接反转前面
如果直接反转前半部分后小了,那么把前面加1再反转,如果大了,减1再反转
还有特殊情况就是本身就是回文的话,需要加一减一都考虑
还有更特殊的情况就是加1减1以后长度变化了,也就是999 1001 这种情况,直接考虑
再有就是小于10的这种情况,直接减1
最后就是出错的100 1000 10000,直接减1
虽然艰辛,但是过了还是很开心
代码有点重复,可以写个函数优化
然后去看了题解,发现基本
class Solution
public String nearestPalindromic(String n)
//最近的回文数
//121513165 最近的回文 121515121 或者 121505121 也就是把中间的1减1,然后回文
//如果长度是偶数,例如 25385693,最近的回文 25388352 或者比它小的 25377352
//如果是 12896 那么一个比它小的就是 12821 比它大的就是 12921
//如果本来是 11199999 那么 11199111 11200211
//那么这样看就是找一个比它大的回文数,一个比它小的回文数,比较哪个差的绝对值最小
//怎么找呢,就是先将前面的一半反转,如果反转的这一半比后面一半大,那么另一个数就是取前面数减1,然后反转
//如果反转的这一半比后一半小,那么前面加1,再反转得到另一个数
int l = n.length();
if(Long.parseLong(n) <= 10)
return String.valueOf(Long.parseLong(n) - 1);
if(Long.parseLong(n) == (long)Math.pow(10, l - 1))
return String.valueOf(Long.parseLong(n) - 1);
int half = l / 2;
String front = n.substring(0, half); //字符串的前半部分
String behind = n.substring(l - half, l); //后半部分
StringBuffer sb = new StringBuffer(front); //反转前半部分
String r_f = sb.reverse().toString(); //将前面反转过来
int r_num = Integer.parseInt(front); //前半部分的值
int r_f_num = Integer.parseInt(r_f); //反转后的值
int b_num = Integer.parseInt(behind); //后半部分的值
int diff = r_f_num - b_num; //差值就等于前半部分和后半部分的差值
//如果本身就是回文,同时加一减一会影响字符串的长度时,特殊处理
if(diff == 0)
long base1 = (long)Math.pow(10, l);
long base2 = (long)Math.pow(10, l - 1);
//System.out.println(base2);
long num = Long.parseLong(n);
//System.out.println(num - base2);
if(n.charAt(0) == '1' && num - base2 == 1)
return String.valueOf(num - 2);
if(n.charAt(0) == '9' && num - base1 == -1)
return String.valueOf(num + 2);
//System.out.println(diff);
//如果反转以后的大,那么需要减1,否则需要加1
int add = diff >= 0 ? -1 : 1;
//如果是奇数的话,需要考虑最中间的数
if(l % 2 == 1)
front = n.substring(0, half + 1);
r_num = Integer.parseInt(front);
String first = front + r_f; //反转前面得到的最终字符串
//将前面加1或者减1
int temp = r_num;
r_num += add;
//System.out.println(r_num);
//前面的字符串最终值
String f_final = String.valueOf(r_num);
front = f_final;
//如果是奇数,那么反转的要少一个字符
if(l % 2 == 1)
front = f_final.substring(0, f_final.length() - 1);
r_num = Integer.parseInt(front);
String b_final = new StringBuffer(front).reverse().toString();
//System.out.println(b_final);
//int b_final_num = Integer.parseInt(b_final);
String finall = f_final + b_final;
//System.out.println(finall);
long diff_new = Math.abs(Long.parseLong(finall) - Long.parseLong(n));
diff = Math.abs(diff);
//如果本身是回文,那么加减都需要考虑,前面考虑了减,现在考虑加
if(diff == 0)
r_num = temp + 1;
//前面的字符串最终值
f_final = String.valueOf(r_num);
front = f_final;
//如果是奇数,那么反转的要少一个字符
if(l % 2 == 1)
front = f_final.substring(0, f_final.length() - 1);
r_num = Integer.parseInt(front);
b_final = new StringBuffer(front).reverse().toString();
String finall2 = f_final + b_final;
diff = (int)Math.abs(Long.parseLong(finall2) - Long.parseLong(n));
if(diff < diff_new)
return finall2;
else
return finall;
if((long)diff > diff_new)
return finall;
else if((long)diff < diff_new)
return first;
//如果大小都相同的话,那么就是返回较小的值
if(Long.parseLong(first) < Long.parseLong(finall))
return first;
else
return finall;
258. 各位相加
2022.3.3 每日一题
题目描述
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。返回这个结果。
示例 1:
输入: num = 38
输出: 2
解释: 各位相加的过程为:
38 --> 3 + 8 --> 11
11 --> 1 + 1 --> 2
由于 2 是一位数,所以返回 2。
示例 1:
输入: num = 0
输出: 0
提示:
0 <= num <= 2^31 - 1
进阶:你可以不使用循环或者递归,在 O(1) 时间复杂度内解决这个问题吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-digits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
递归
class Solution
public int addDigits(int num)
//想想该怎么弄成O1复杂度
//先写个递归吧
if(num < 10)
return num;
int res = 0;
while(num != 0)
res += num % 10;
num /= 10;
return addDigits(res);
这个O1的方法想不出来,看题解吧
主要是这个式子
class Solution
public int addDigits(int num)
//想想该怎么弄成O1复杂度
//先写个递归吧
//这样,这个数最大是2的31次方-1,也就是2147483647
//最大的十个数相加就是 1999999999,也就是82
//那么再看所有返回的个位数,也就是1-9
//1的情况就是 10
//2的情况就是 20 11
//3的情况就是 30 21 12
//4的情况就是 40 31 22 13
//以此类推
//推不下去
//看了官解的数学解法,我肯定是想不出来的
//观察那个公式,可以发现,公式中前面的连加式是9的倍数,后面的式子是所有位置的和
//然后将这个数对 9 取余,那么可以发现只剩下后面那个部分对9取余,也就是所有的位置数字之和对9取余,
//所以就可以得到一个结论,就是num与所有位置数字之和 对9同余
//而一直将这个相加的数字对9取余,可以得到最后的个位数与num对9是同余的
//得到这个结论以后,我们就可以根据num是否是9的倍数分成两种情况,如果不是9的倍数,那么剩下的那个数就是num%9
//如果是9的倍数,那么对9取余以后得到的0,所以最后结果是9
//最后又做了个操作,就是用num - 1对9取余然后加1,因为对9取余的结果是 0-8 ,而各位相加的结果在 1-9 这个范围内
//所以用这样的操作,直接得到最终的结果
//对于剩下的0,0减1对9取余就是-1,然后加1是0,所以不用单独处理
return (num - 1) % 9 + 1;
以上是关于LeetCode 6. Z 字形变换 / 564. 寻找最近的回文数 / 258. 各位相加的主要内容,如果未能解决你的问题,请参考以下文章