本周每日一题 题目
- lc273. 整数转换英文表示
- lc29. 两数相除
- lc412. Fizz Buzz
- 剑指 Offer II 069. 山峰数组的顶部
- lc38. 外观数列
- lc282. 给表达式添加运算符
- lc230. 二叉搜索树中第K小的元素
10-11 lc273. 整数转换英文表示
- 这题真是把我恶心到了,没有给数字与单词的映射表,我真是服了,自己敲半天,而且我单词敲错了好几个,真是书白读了
- 不过还算是好题,我的思路是先解决十亿和百万的级别,逻辑为,用 i i i 标识当前位,用 e x c e e d exceed exceed 来标识超出当前档次的数位,比如当前是9位,就是超过了7位的百万2位
- 然后百万以下的单独算,也是一样的逻辑,先来弄千,再来百,然后每次都是先处理超过的部分,再加上当前的档次,然后再处理后序的部分。在这中间,需要单独处理0
- 整体挺复杂的,写的脖子发酸
- 稍微有点乱,不过其实还好
class Solution {
private static Map<Integer,String> map = new HashMap<>(){{
put(1,"One ");
put(2,"Two ");
put(3,"Three ");
put(4,"Four ");
put(5,"Five ");
put(6,"Six ");
put(7,"Seven ");
put(8,"Eight ");
put(9,"Nine ");
put(10,"Ten ");
put(11,"Eleven ");
put(12,"Twelve ");
put(13,"Thirteen ");
put(14,"Fourteen ");
put(15,"Fifteen ");
put(16,"Sixteen ");
put(17,"Seventeen ");
put(18,"Eighteen ");
put(19,"Nineteen ");
put(20,"Twenty ");
put(30,"Thirty ");
put(40,"Forty ");
put(50,"Fifty ");
put(60,"Sixty ");
put(70,"Seventy ");
put(80,"Eighty ");
put(90,"Ninety ");
}};
private static char[] ss;
public static String numberToWords(int num) {
ss = String.valueOf(num).toCharArray();
int n = ss.length;
StringBuilder sb = new StringBuilder();
for(int i=0; i<n; i++){
if(ss[i]=='0'){
if(n==1) return "Zero";
continue;
}
int bit = n - i;
if(bit>=10){
sb.append(help(i,bit-9));
sb.append("Billion ");
i += bit -10;
}
else if(bit>=7){
sb.append(help(i,bit-6));
sb.append("Million ");
i += bit -7;
}
else{
sb.append(help(i,bit));
break;
}
}
return sb.toString().trim();
}
private static String help(int i, int exceedBit){
if(exceedBit<=0) return "";
if(ss[i]=='0') return help(i+1,exceedBit-1);
StringBuilder sb = new StringBuilder();
if(exceedBit>=4){
sb.append(help(i,exceedBit-3));
sb.append("Thousand ");
sb.append(help(i+exceedBit-3,3));
}
else if(exceedBit>=3){
sb.append(help(i,exceedBit-2));
sb.append("Hundred ");
sb.append(help(i+exceedBit-2,2));
}
else{
int num = Integer.valueOf(new String(ss,i,exceedBit));
if(num==0) return "";
if(num>=20){
sb.append(map.get(num/10*10));
sb.append(help(i+1,exceedBit-1));
}
else sb.append(map.get(num));
}
return sb.toString();
}
}
10-12 lc29. 两数相除
- 因为不能用乘法,除法,所以想法就是用2^n来进行减法
- 每次减去2^n*divisor,然后就能够快速逼近0了。这里的乘法用位运算来代替
- 而结果就是 2 i + 2 j + . . . 2^i + 2^j +... 2i+2j+...
class Solution {
public int divide(int dividend, int divisor) {
if(divisor==0) return 0;
if(dividend==Integer.MIN_VALUE&&divisor==-1) return Integer.MAX_VALUE;
int sign = (dividend>=0&&divisor>=0)||(dividend<0&&divisor<0)?1: -1;
int res = 0;
long t = Math.abs((long)dividend);
long d = Math.abs((long)divisor);
for(int i=31; i>=0; i--){
if((t>>i)>=d){
t -= d<<i;
res += 1<<i;
}
}
return res * sign;
}
}
10-13 lc412. Fizz Buzz
class Solution {
public List<String> fizzBuzz(int n) {
List<String> res = new ArrayList<>();
for(int i=1; i<=n; i++){
if(i%5==0&&i%3==0) res.add("FizzBuzz");
else if(i%5==0) res.add("Buzz");
else if(i%3==0) res.add("Fizz");
else res.add(String.valueOf(i));
}
return res;
}
}
10-14 剑指 Offer II 069. 山峰数组的顶部
- 就是一个二分查找的简单题
- 这里用r-l==1来防止查询二分时死循环,是一个可以重复使用的trick
class Solution {
public int peakIndexInMountainArray(int[] arr) {
int l = 0, r = arr.length-1;
while(l<r){
if(r-l==1) return arr[l]>arr[r]?l:r;
int mid = (l+r) / 2;
if(arr[mid]>arr[mid-1]) l = mid;
else r = mid -1;
}
return l;
}
}
10-15 lc38. 外观数列
- 之前做过这题,虽然已经是秋招7月份的事了
- 这一题我是用模拟来做的,每次读取上面一行,然后挨个统计个数,来生成新的一行
- 逻辑在于:如果当前和前一个不等,则记录前一个;如果相等,则cnt++。然后到达右边界在单独添加到结果中
- 然后这里的左边界,我是选择直接从n=2开始,这样就可以避免
class Solution {
public String countAndSay(int n) {
if(n<=0) return "";
if(n==1) return "1";
String s = "11";
for(int i=2; i<n; i++){
StringBuilder sb = new StringBuilder();
char[] ss = s.toCharArray();
int cnt = 1;
for(int j=1; j<ss.length; j++){
if(ss[j]!=ss[j-1]){
sb.append(cnt);
sb.append(ss[j-1]);
cnt = 1;
}
else cnt++;
if(j+1==ss.length){
sb.append(cnt);
sb.append(ss[j]);
}
}
s = sb.toString();
}
return s;
}
}
10-16 lc282. 给表达式添加运算符
- 这题写了很久很久,真的很恶心
- 首先是题目整体的思路不难,但是很多边界,还有恶心的地方
- 思路为:最多10个数字,也就是有9个位置,四种选择, + − ∗ 不 加 +-*不加 +−∗不加,又因为题意要求返回所有等于target的结果,那么枚举所有是必须的了,所以有4^9种情况。这就是个回溯的问题。然后就是将所有的表达式来进行判断,是否和target相等
- 以上是简单的思路,这里我是直接用到了之前的计算表达式II的代码
- 当然,这样比较慢,也可以在枚举的过程中直接计算,这样也可以,而且会快很多
- 恶心的地方在于,还要考虑当前字母是否为0,然后0的话要看前面有的是数字还是符号,如果是符号,那后面必为符号
- 然后还有就是target可能是-2^32,这个也是题目恶心人的地方,所以t设置为long,防止溢出
class Solution {
private static long t;
private static List<String> res;
public static List<String> addOperators(String num, int target) {
t = (long)target;
res = new ArrayList<>();
StringBuilder sb = new StringBuilder();
enumerate(num.toCharArray(),sb,0);
return res;
}
private static void enumerate(char[] num,StringBuilder sb,int index){
if(index==num.length-1){
sb.append(num[index]);
String s = sb.toString();
if(calc(s)==t)
res.add(s);
sb.deleteCharAt(sb.length()-1);
return;
}
char ch = num[index];
sb.append(ch);
sb.append('*');
enumerate(num,sb,index+1);
sb.deleteCharAt(sb.length()-1);
sb.append('+');
enumerate(num,sb,index+1);
sb.deleteCharAt(sb.length()-1);
sb.append('-');
enumerate(num,sb,index+1);
sb.deleteCharAt(sb.length()-1);
if(ch!='0'||(index!=0&&Character.isDigit(sb.charAt(sb.length()-2))))
enumerate(num,sb,index+1);
sb.deleteCharAt(sb.length()-1);
}
private static long calc(String s){
char preSign = '+';
Deque<Long> stack = new LinkedList<>();
char[] ss = s.toCharArray();
int n = ss.length;
long cur = 0;
for(int i=0; i<n; i++){
char ch = ss[i];
if(Character.isDigit(ch)) cur = cur*10+ch-'0';
if(ch==' '&&i!=n-1) continue;
if(!Character.isDigit(ch)||i==n-1){
if(preSign=='+') stack.push(cur);
else if(preSign=='-') stack.push(cur*-1);
else if(preSign=='*') stack.push(stack.pop()*cur);
else if(preSign=='/') stack.push(stack.pop()/cur);
cur = 0;
preSign = ch;
}
}
long res = 0;
while(!stack.isEmpty()) res += stack.pop();
return res;
}
}
10-17 lc230. 二叉搜索树中第K小的元素
- BST,所以中序遍历就可以,想了一会儿,如果一个方法,确实没办法直接输出结果
- 所以两个方法,一个dfs,一个api调用
- 然后逻辑是:用cnt表示当前第几个,res代表第几个值,然后中序遍历,每次都cnt–,只要一旦cnt为0,则直接返回,所以dfs中有两个return
- 这次的代码比之前第一次写的要快很多,因为有剪枝
class Solution {
private static int res;
private static int cnt;
public static int kthSmallest(TreeNode root, int k) {
cnt = k;
help(root);
return res;
}
private static void help(TreeNode root){
if(cnt<=0||root==null) return;
help(root.left);
cnt--;
if(cnt<0) return;
res = root.val;
help(root.right);
}
}