《剑指offer》-- 把数组排成最小的数、丑数、二进制中1的个数、表示数值的字符串、替换空格
一、把数组排成最小的数:
1、题目:
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
2、解题思路:
重写Comparator的compare()方法。
3、代码实现:
public class Test23 {public static void main(String[] args) {int[] array = new int[]{6,2,4,41,5};PrintMinNumber(array);}//解题思路://通过比较器重写compare方法public static String PrintMinNumber(int [] numbers) {ArrayList<Integer> list = new ArrayList<>();for(int i=0;i<numbers.length;i++){list.add(numbers[i]);}Collections.sort(list,new Comparator<Integer>(){@Overridepublic int compare(Integer o1, Integer o2) {String str1=o1+""+o2;String str2=o2+""+o1;return str1.compareTo(str2);}});StringBuilder builder = new StringBuilder();for(Integer num:list){builder.append(num);}System.out.println(builder.toString());return builder.toString();}
}
二、丑数:
1、题目:
把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
2、解题思路:
参考牛客网的“事无巨细,悉究本末”:https://www.nowcoder.com/questionTerminal/6aa9e04fc3794f68acf8778237ba065b
2.1 通俗易懂的解释:
首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,我们发现这种方法会得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的。那么我们可以维护三个队列:
(1)丑数数组: 1
乘以2的队列:2
乘以3的队列:3
乘以5的队列:5
选择三个队列头最小的数2加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(2)丑数数组:1,2
乘以2的队列:4
乘以3的队列:3,6
乘以5的队列:5,10
选择三个队列头最小的数3加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(3)丑数数组:1,2,3
乘以2的队列:4,6
乘以3的队列:6,9
乘以5的队列:5,10,15
选择三个队列头里最小的数4加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(4)丑数数组:1,2,3,4
乘以2的队列:6,8
乘以3的队列:6,9,12
乘以5的队列:5,10,15,20
选择三个队列头里最小的数5加入丑数数组,同时将该最小的数乘以2,3,5放入三个队列;
(5)丑数数组:1,2,3,4,5
乘以2的队列:6,8,10,
乘以3的队列:6,9,12,15
乘以5的队列:10,15,20,25
选择三个队列头里最小的数6加入丑数数组,但我们发现,有两个队列头都为6,所以我们弹出两个队列头,同时将12,18,30放入三个队列;
……………………
2.2 疑问:
2.2.1 为什么分三个队列?
丑数数组里的数一定是有序的,因为我们是从丑数数组里的数乘以2,3,5选出的最小数,一定比以前未乘以2,3,5大,同时对于三个队列内部,按先后顺序乘以2,3,5分别放入,所以同一个队列内部也是有序的;
2.2.2 为什么比较三个队列头部最小的数放入丑数数组?
因为三个队列是有序的,所以取出三个头中最小的,等同于找到了三个队列所有数中最小的。
2.3 实现思路:
我们没有必要维护三个队列,只需要记录三个指针显示到达哪一步;“|”表示指针,arr表示丑数数组;
(1)1
|2
|3
|5
目前指针指向0,0,0,队列头arr[0] * 2 = 2, arr[0] * 3 = 3, arr[0] * 5 = 5
(2)1 2
2 |4
|3 6
|5 10
目前指针指向1,0,0,队列头arr[1] * 2 = 4, arr[0] * 3 = 3, arr[0] * 5 = 5
(3)1 2 3
2| 4 6
3 |6 9
|5 10 15
目前指针指向1,1,0,队列头arr[1] * 2 = 4, arr[1] * 3 = 6, arr[0] * 5 = 5
………………
3、代码实现:
public class Test24 {//解题思路:创建三个队列 https://www.nowcoder.com/ta/coding-interviewspublic int GetUglyNumber_Solution(int index) {if(index<7)return index;//创建三个队列的头指针,newNum代表的是选出的最小数int t2=0,t3=0,t5=0;int newNum=1;//创建一个数组,存放丑数ArrayList<Integer> list = new ArrayList<>();list.add(newNum);for(int i=1;i<index;i++){//选出三个队列里面最小的数 newNum=Math.min(list.get(t2)*2,Math.min(list.get(t3)*3,list.get(t5)*5));//这三个if有可能进入一个或者多个,进入多个是三个队列头最小的数有多个的情况if(newNum == list.get(t2)*2) t2++; if(newNum == list.get(t3)*3) t3++; if(newNum == list.get(t5)*5) t5++; list.add(newNum);}return newNum;}
}
三、二进制中1的个数:
1、题目:
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
2、思路:
第一种:使用java内置的的toBinaryString方法来实现;
第二种:利用位运算符来实现:
(1)将n与n-1做与运算,会把最右边的1去掉。比如: 1100 & 1011 = 1000 ,即 12 & 11 = 8,再利用计算器count++计算出有多少个 1 即可。
(2)详细说明:如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来他的二进制处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
(3)举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011。我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
3、代码实现:
//利用java内置的toBinaryString方法来实现:public static int NumberOf1(int n){int count = 0;String str=Integer.toBinaryString(n);for(int i=0;i<str.length();i++){if(str.charAt(i)=='1'){count++;}}return count;}//利用位运算符来实现:public static int NumberOf2(int n){int count = 0;if(n==0)return count;if(n!=0){while(n!=0){count++;n=n&(n-1);}}return count;}
四、表示数值的字符串:
1、题目:
实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
2、代码实现:
public class Test11 {private int index = 0;//第二种解法:剑指offer解法:public boolean isNumeric(char[] str){if(str.length<1){return false;}boolean flag = scanInteger(str);if(index<str.length && str[index]=='.'){index++;flag = scanUnsignedInteger(str) || flag;}if(index < str.length && (str[index] =='E' || str[index]=='e')){index++;flag = flag && scanInteger(str);}return flag && index == str.length;}private boolean scanInteger(char[] str){if(index<str.length && (str[index]=='+' || str[index]=='-') )index++;return scanUnsignedInteger(str);}private boolean scanUnsignedInteger(char[] str) {int start = index;while(index < str.length && str[index]>='0' && str[index] <='9')index++;return start<index;//是否存在整数}//第一种解法:正则表达式public boolean isNumeric1(char[] str) {String string = String.valueOf(str);return string.matches("[\\+\\-]?\\d*(\\.\\d+)?([eE][\\+\\-]?\\d+)?");}/*以下对正则进行解释:[\\+\\-]? -> 正或负符号出现与否\\d* -> 整数部分是否出现,如-.34 或 +3.34均符合(\\.\\d+)? -> 如果出现小数点,那么小数点后面必须有数字;否则一起不出现([eE][\\+\\-]?\\d+)? -> 如果存在指数部分,那么e或E肯定出现,+或-可以不出现,紧接着必须跟着整数;或者整个部分都不出现*/
}
四、替换空格:
1、题目描述:
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
2、解题思路:
第一种:从前往后替换,后面的字符要不断往后移动,要多次移动,所以效率低下;
第二种:从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只为移动一次,这样效率更高一点。
3、代码实现:
public String replaceSpace(StringBuffer str) {int spaceNum = 0;//原字符串中空格的个数for(int i = 0;i<str.length();i++){if(str.charAt(i)==' '){spaceNum++;}}int indexOld = str.length()-1;//indexOld为为替换前的str下标int newLength = str.length() + spaceNum*2;//计算空格转换成%20之后的str长度int indexNew = newLength -1;//indexNew为为把空格替换为%20后的str下标str.setLength(newLength);;//使str的长度扩大到转换成%20之后的长度,防止下标越界for(;indexOld>=0 && indexOld<indexNew;--indexOld){if(str.charAt(indexOld)==' '){str.setCharAt(indexNew--, '0');str.setCharAt(indexNew--, '2');str.setCharAt(indexNew--, '%');}else{str.setCharAt(indexNew--, str.charAt(indexOld));}}return str.toString();}
}
《剑指offer》-- 把数组排成最小的数、丑数、二进制中1的个数、表示数值的字符串、替换空格相关推荐
- 剑指offer 把数组排成最小的数 atoi和itoa,pow
pow(x,y)在#include<math.h>文件中,计算x的y次方. C++引入头文件:#include <stdlib.h> 或者 #include <cstdl ...
- 剑指offer 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组 ...
- [剑指offer] 旋转数组的最小数字
本文首发于我的个人博客:尾尾部落 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2 ...
- 4-剑指offer: 把数组排成最小的数
题目描述 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 代码: cl ...
- java中数组的下标比较_【Java】 剑指offer(53-3) 数组中数值和下标相等的元素
本文参考自<剑指offer>一书,代码采用Java语言. 题目 假设一个单调递增的数组里的每个元素都是整数并且是唯一的.请编程实现一个函数找出数组中任意一个数值等于其下标的元素.例如,在数 ...
- 【LeetCode】剑指 Offer 51. 数组中的逆序对
[LeetCode]剑指 Offer 51. 数组中的逆序对 文章目录 [LeetCode]剑指 Offer 51. 数组中的逆序对 package offer;public class Soluti ...
- 【LeetCode】剑指 Offer 56. 数组中数字出现的次数
[LeetCode]剑指 Offer 56. 数组中数字出现的次数 文章目录 [LeetCode]剑指 Offer 56. 数组中数字出现的次数 package offer;import java.u ...
- 【LeetCode】剑指 Offer 39. 数组中出现次数超过一半的数字
[LeetCode]剑指 Offer 39. 数组中出现次数超过一半的数字 文章目录 [LeetCode]剑指 Offer 39. 数组中出现次数超过一半的数字 一.摩尔投票法 一.摩尔投票法 核心理 ...
- 剑指 Offer II 061. 和最小的 k 个数对
链接:剑指 Offer II 061. 和最小的 k 个数对 题解: class Solution { public:vector<vector<int>> kSmallest ...
最新文章
- 揭秘:一个月不摸鱼能写多少代码?
- 阿里钉钉陈航发布10亿“春雨计划”,推进企业级市场服务创新
- 8.使用Xshell5密钥登录liunx
- 5G 非独立组网链路预算公式(笔记)
- JaveWeb学习之Servlet(二):ServletConfig和ServletContext
- 免费12个月!阿里云助力中小企业0成本上云
- Python学习中出现的一些问题
- html5下input的placeholder标签兼容ie9
- java停止循环label_Java中的break Label 和continue Label 例子(跳出多重循环)(转)...
- cmd编译java代码
- 心理声学模型在感知音频编码中的应用
- NXOPEN/UG二次开发C#---获取NX的版本
- vue 获取汉字的全拼、简拼、首拼
- 我如何把薪水从 50人民币/天 提升到 100美元/小时的 (3)
- 图片上传 axios
- 小张张带你学习css美化网页,让你在学习的道路上不再孤单
- Maven插件仓库地址
- 微信小程序清除缓存clearStorageSync和removeStorageSync的区别 清除缓存问题 数据缓存详解
- 【关于打印errno]
- 腾讯、阿里之后,今日头条也入局的视频通信行业!