168. Excel表列名称(简单)
给你一个整数
columnNumber
,返回它在 Excel 表中相对应的列名称。例如:
A -> 1 B -> 2 C -> 3 ... Z -> 26 AA -> 27 AB -> 28 ...示例 1:
输入:columnNumber = 1 输出:"A"示例 2:
输入:columnNumber = 28 输出:"AB"示例 3:
输入:columnNumber = 701 输出:"ZY"示例 4:
输入:columnNumber = 2147483647 输出:"FXSHRXW"提示:
1 <= columnNumber <= 2^31 - 1
解法一、进制转换
相当于26进制中0-25变成了1-26,每轮开始之前减回去就好
class Solution {
public:
string convertToTitle(int columnNumber) {
string ans;
while(columnNumber) {
--columnNumber;
int re = columnNumber % 26;
ans.push_back('A' + re);
columnNumber /= 26;
}
reverse(ans.begin(), ans.end());
return ans;
}
};
670. 最大交换(中等)
给定一个非负整数,你至多可以交换一次数字中的任意两位。返回你能得到的最大值。
示例 1 :
输入: 2736 输出: 7236 解释: 交换数字2和数字7。示例 2 :
输入: 9973 输出: 9973 解释: 不需要交换。注意:
- 给定数字的范围是 [0, 10^8]
解法一、暴力
i从前往后,j从后往前,寻找最大值。当最大值有复数个的时候,找最后一个。
第二个循环交换,时间复杂度O(n^2)
class Solution {
public static int maximumSwap(int num) {
String a = String.valueOf(num);
StringBuffer sb = new StringBuffer();
int left = -1,right = -1;
for(int i = 0;i<a.length();i++){
for(int j = a.length()-1;j > i;j--){
if(a.charAt(j) > a.charAt(i) && (right == -1 || a.charAt(j) > a.charAt(right))){
left = i;
right = j;
}
}
if((left ^ right) != 0)break;
}
for(int i = 0;i < a.length();i++){
if(i == left){
sb.append(a.charAt(right));
} else if(i == right) {
sb.append(a.charAt(left));
}else{
sb.append(a.charAt(i));
}
}
return Integer.parseInt(sb.toString());
}
}
解法二、枚举
其实就是全转一遍,一共有28种方法。感觉这个转字符组然后swap的方式很有意思
class Solution {
public int maximumSwap(int num) {
char[] charArray = String.valueOf(num).toCharArray();
int n = charArray.length;
int maxNum = num;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
swap(charArray, i, j);
maxNum = Math.max(maxNum, Integer.parseInt(new String(charArray)));
swap(charArray, i, j);
}
}
return maxNum;
}
public void swap(char[] charArray, int i, int j) {
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/maximum-swap/solutions/1818457/zui-da-jiao-huan-by-leetcode-solution-lnd5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
解法三、贪心
和解法一差不多,但是只需要一次循环。从右往左遍历,用maxId记录最大值的下标,其中满足(如果最大值只有一个,记录最大值;如果最大值有多个,记录最靠右的)。之后再往左看,一旦有小的就更新,记录值对。
class Solution {
public int maximumSwap(int num) {
char[] charArray = String.valueOf(num).toCharArray();
int n = charArray.length;
int maxIdx = n - 1;
int idx1 = -1, idx2 = -1;
for (int i = n - 1; i >= 0; i--) {
if (charArray[i] > charArray[maxIdx]) {
maxIdx = i;
} else if (charArray[i] < charArray[maxIdx]) {
idx1 = i;
idx2 = maxIdx;
}
}
if (idx1 >= 0) {
swap(charArray, idx1, idx2);
return Integer.parseInt(new String(charArray));
} else {
return num;
}
}
public void swap(char[] charArray, int i, int j) {
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/maximum-swap/solutions/1818457/zui-da-jiao-huan-by-leetcode-solution-lnd5/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
233. 数字 1 的个数(困难)
给定一个整数
n
,计算所有小于等于n
的非负整数中数字1
出现的个数。示例 1:
输入:n = 13 输出:6示例 2:
输入:n = 0 输出:0提示:
0 <= n <= 10^9
解法一、分类讨论
见↓
. - 力扣(LeetCode)
class Solution {
public int countDigitOne(int n) {
int m = 1;
int ans = 0;
while (n >= m){
ans += (1+(n/m-1)/10)*m;
if (n/m%10 == 1) ans = ans-m+1+n%m;
m *= 10;
}
return ans;
}
}
作者:嘉然
链接:https://leetcode.cn/problems/number-of-digit-one/solutions/937955/gong-shi-tui-dao-qiu-mei-yi-wei-shang-1d-5qvu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
357. 统计各位数字都不同的数字个数
给你一个整数
n
,统计并返回各位数字都不同的数字x
的个数,其中0 <= x < 10n
。示例 1:
输入:n = 2 输出:91 解释:答案应为除去11、22、33、44、55、66、77、88、99
外,在 0 ≤ x < 100 范围内的所有数字。示例 2:
输入:n = 0 输出:1提示:
0 <= n <= 8
解法一、打表
抖个机灵(
解法二、排列组合
0位有一个(0),个位有十个(0-9),再往上,例如两位数,有9*9,三位数有9*9*8···
class Solution {
public int countNumbersWithUniqueDigits(int n) {
if (n == 0) {
return 1;
}
if (n == 1) {
return 10;
}
int res = 10, cur = 9;
for (int i = 0; i < n - 1; i++) {
cur *= 9 - i;
res += cur;
}
return res;
}
}
解法三、动态规划
状态转移方程
dp[i]=dp[i-1]+(dp[i-1] - dp[i-2]) * (10 - (i-1))
class Solution {
//对于1位数,全都可以,10。二位数,9*9.对于三位数,9*9*8 对于四位数 9*9*8*7
public int countNumbersWithUniqueDigits(int n) {
if(n ==0)return 1;
int[] dp = new int[n+1];
dp[0] = 1;
dp[1] = 10;
for(int i = 2;i <= n;i++){
dp[i] = dp[i-1] + (dp[i-1]-dp[i-2])*(11-i);
}
return dp[n];
}
}
400. 第 N 位数字
给你一个整数
n
,请你在无限的整数序列[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...]
中找出并返回第n
位上的数字。示例 1:
输入:n = 3 输出:3示例 2:
输入:n = 11 输出:0 解释:第 11 位数字在序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 里是 0 ,它是 10 的一部分。提示:
1 <= n <= 2^31 - 1
解法一、模拟遍历
这次真有点在乱命名了···i是位数,t是模拟那个9/90/900的每位数总值,pre是sum的上一格记录。while里确认区间,n所在的位置是[pre,sum],然后回退超出了一格的i,减pre把n在本位上多出来的留出。k计算余数(这里用了168题的算法,对于只有1——n而非0——n-1的数字,求余应该是(x-1) %t +1),num是最终的数字。用最后一行把num的个位变成所求位,返回10的余数(即个位)。
class Solution {
//1-9 1 10-99 2/ 180 100-999 3/2700 1000-9999 4 36000
//181 如果是50 对应的是2位数
// 9 90 900 9000 90000 900000
public static int findNthDigit(int n) {
if(n < 10)return n;
long pre = 0;
long sum = 0,i = 1,t = 9;
while(sum < n){
pre = sum;
sum += t * i;
t*=10;
i++;
}
i--;
n -=pre;
long k = (n-1) % i + 1;
long num = t / 90 + (n-1) / i;//假如是59987的第四位,i = 5,num = 59987,k = 4;
num /=(int) Math.pow(10,i-k);
return (int)num % 10;
}
}
题解区更明确的。(这个while的目的一致,写法不同)
public int findNthDigit(int n) {
int digit = 1; // n所在数字有几位数
long start = 1; // 每digit位的起始数字,1位数从2开始,2位数从10开始..
long count = 9; // 所有digit位数的数位数量, 所有1位数有9个位,所有的2位数90x2个位..
// 1. 确定n所在的数字的位数digit
while (n > count) {
n -= count; // n分别减去1位数 2位数 3位数的个数..
digit += 1;
start *= 10;
count = 9 * start * digit;
}
long num = start + (n - 1) / digit; // 2. 确定n所在的数字num,n-1是从0开始计算偏移量
int x = (n - 1) % digit; // 3. 确定所求数位是 num 的第几位数字,从0算起
// 从num中分割出第x位,如 num = 1234, x = 1, 需割掉2位数,再求模可得2
int times = digit - (x + 1);
for (int i = 0; i < times; i++) num /= 10;
return (int)(num % 10);
}
碎碎念
- 168学到了1-n位进制转换,670学会了单向遍历,233挺难的考察分类讨论,357靠自己写出了动态规划,400要考虑的太碎了,很多边界情况。。。。
- 明天开始出门!路上两天,休息一周多点,再之后回学校了~