一、最小的淘气值
题目:
/** * 老师要给学生安排座位,经统计教室有N个双人桌,M名学生,每个学生有一个淘气值, * 要合理安排座位,使得班内同桌之和的淘气值最大值尽可能的小,输出最小值。 */
这是一道360Android春招笔试题
要考虑这样的几种情况:
1.座位数>=学生数,那么就每个人做一个桌子,最大的淘气值就是最淘气的那个学生
2.座位数刚好坐满,那么就对淘气值排序,让最大的和最小的坐一起,然后找到和最大的值返回
3.有学生自己坐一桌,那也先对淘气值排序,让最淘气的都自己坐着去,然后其它人较大的和较小的坐一起,返回这些桌子淘气值最大的
这里的排序我用的快速排序,你可以替换为自己的排序方式
public static void test1(){
Scanner scanner=new Scanner(System.in);
int m=scanner.nextInt();
int n=scanner.nextInt();
int student[] =new int[m];
for (int i=0;i<m;i++){
student[i]=scanner.nextInt();
}
int dan=2*n-m;
System.out.println(dan);
SortMethods.kuaiSu(student,0,m-1);
if (n>=m){
System.out.println(student[m-1]);
}else {
for (int i=0;i<(m-dan)/2;i++){
student[i]+=student[m-1-i-dan];
}
SortMethods.kuaiSu(student,0,n-dan);
System.out.println(student[n-dan]);
}
}
二、列名称
题目:
/*** * 给定一个正整数,返回它在 Excel 表中相对应的列名称。 * * 例如, * * 1 -> A * 2 -> B * 3 -> C * ... * 26 -> Z * 27 -> AA * 28 -> AB * ... * * 示例 1: * 输入: 1 * 输出: "A" * * 示例 2: * 输入: 28 * 输出: "AB" * * 示例 3: * 输入: 701 * 输出: "ZY" */
说到底,这是一道进制转换的题,把10进制转换为27进制,不是26,满26不进
这也是为什么要在循环里面减一的原因
public static String method1(int n){
StringBuilder sb = new StringBuilder();
while (n > 0) {
n--;
sb.append((char) (n % 26 + 'A'));
n =n / 26;
}
return sb.reverse().toString();
}
与之相似的题目:
/** * 给定一个Excel表格中的列名称,返回其相应的列序号。 * * 例如, * * A -> 1 * B -> 2 * C -> 3 * ... * Z -> 26 * AA -> 27 * AB -> 28 * ... * * 示例 1: * 输入: "A" * 输出: 1 * * 示例 2: * 输入: "AB" * 输出: 28 * * 示例 3: * 输入: "ZY" * 输出: 701 */
这道题就是把刚才转换的列名称转换回来
顺着刚才的思路,每次循环加一
public static int method1(String s) {
if (s==null||s.equals(""))return 0;
int length=s.length()-1;
int n=0;
int result=0;
while (length>-1){
result+=Math.pow(26,n)*(s.charAt(length)-64);
n++;
length--;
}
return result;
}
优化代码:
public static int method2(String s) {
if (s==null||s.equals(""))return 0;
int result=0;
for (int i = 0; i < s.length(); i++) {
int tmp = (int)Math.pow(26, s.length()-i-1);
result += (s.charAt(i)-'A'+1) * tmp;
}
return result;
}
再优化:
public static int method3(String s){
int res = 0;
for (int i = s.length() - 1,j=0; i >= 0; --i)
{
res += (s.charAt(i) - 'A' + 1)*Math.pow(26, j++) ;
}
return res;
}
三、尾数中零的数量
题目:
/** * 给定一个整数 n,返回 n! 结果尾数中零的数量。 * 示例 1: * 输入: 3 * 输出: 0 * 解释: 3! = 6, 尾数中没有零。 * 示例 2: * 输入: 5 * 输出: 1 * 解释: 5! = 120, 尾数中有 1 个零. */
看到这道题第一时间的想法就是,求出n!,然后不断判断最后一位,除10
事实证明这种不考虑数的上限的做法是完全行不通的
public static int method1(int n) {
if (n<1)return 0;
int number=1,result=0;
while (n>1){
number*=n--;
}
while (number>10){
if (number%10==0)result++;
number/=10;
}
return result;
}
那么就要思考一下如何在尾数中产生0了?
尾数中0的数量就是乘了多少个10嘛,只有乘10或者10的倍数才能在尾数中产生0
10=2*5
然而一串连续的数字中,分解为质因数,2的数量肯定比5多,那么就是找5的数量喽
public static int method2(int n) {
int num = 0;
while (n > 0) {
n /= 5;
num += n;
}
return num;
}
四、旋转数组
题目:
/** * 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 * * 示例 1: * 输入: [1,2,3,4,5,6,7] 和 k = 3 * 输出: [5,6,7,1,2,3,4] * 解释: * 向右旋转 1 步: [7,1,2,3,4,5,6] * 向右旋转 2 步: [6,7,1,2,3,4,5] * 向右旋转 3 步: [5,6,7,1,2,3,4] * * 示例 2: * 输入: [-1,-100,3,99] 和 k = 2 * 输出: [3,99,-1,-100] * 解释: * 向右旋转 1 步: [99,-1,-100,3] * 向右旋转 2 步: [3,99,-1,-100] * * 说明: * 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。 * 要求使用空间复杂度为 O(1) 的原地算法。 */
主要的限制就是空间复杂度O(1)的原地算法,不然使用俩数组拼接,很简单就能完成
可以用双层for循环,循环k次,每次记住后面要移动到前面来的一个数,然后将该数前方的所有数后移一位
public static void method1(int[] nums, int k) {
int swap,pos;
k=k%nums.length;
for (int i=1;i<=k;i++){
pos=nums.length-1-(k-i);
swap=nums[pos];
for (int j=pos;j>=i;j--){
nums[j]=nums[j-1];
}
nums[i-1]=swap;
}
}
或者整体后移k次,每次记住最后的那个数
public static void method2(int[] nums,int k){
int n = nums.length;
k %= n;
for (int i = 0; i < k; i++) {
int temp = nums[n - 1];
for (int j = n - 1; j > 0; j--) {
nums[j] = nums[j - 1];
}
nums[0] = temp;
}
}
加一些技巧:
先将整体反转:把后面的数变道前面了
再把前k个数反转,这样前k个数顺序调整正确了,也把需要调整的位置的数调整了
再把最后的数反转,原因同上
完成
public static void method3(int[] nums,int k){
int n = nums.length;
k %= n;
reverse(nums, 0, n - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
}
private static void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start++] = nums[end];
nums[end--] = temp;
}
}
下面的这种方法大同小异,不太好想
public static void method4(int[] nums,int k){
int n = nums.length;
k %= n;
// 第一次交换完毕后,前 k 位数字位置正确,后 n-k 位数字中最后 k 位数字顺序错误,继续交换
for (int start = 0; start < nums.length && k != 0; n -= k, start += k, k %= n) {
for (int i = 0; i < k; i++) {
swap(nums, start + i, nums.length - k + i);
}
}
}
private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
使用递归
public static void method5(int[] nums,int k){
recursiveSwap(nums, k, 0, nums.length);
}
private static void recursiveSwap(int[] nums, int k, int start, int length) {
k %= length;
if (k != 0) {
for (int i = 0; i < k; i++) {
swap(nums, start + i, nums.length - k + i);
}
recursiveSwap(nums, k, start + k, length - k);
}
}