《程序员面试宝典》解题报告2-牛客

比较经典的一些题:31、32、37、38、40、41、44、45、46、47、48、49、50、51、52、54、56、57、58、59、60

31、找出缺失的整数

题目描述
数组A包含了0到n的所有整数,但其中缺失了一个。对于这个问题,我们设定限制,使得一次操作无法取得数组number里某个整数的完整内容。唯一的可用操作是询问数组中第i个元素的二进制的第j位(最低位为第0位),该操作的时间复杂度为常数,请设计算法,在O(n)的时间内找到这个数。
给定一个数组number,即所有剩下的数按从小到大排列的二进制各位的值,如A[0][1]表示剩下的第二个数二进制从低到高的第二位。同时给定一个int n,意义如题。请返回缺失的数。
测试样例:
[[0],[0,1]]
返回:1

import java.util.*;
/*
位运算的一种思路:
另外的一道题,找出不重复的数字
任意一个数字与本身异或都是0
把0~n都异或一次,然后再与数组中的数异或,结果就是缺失的整数
但是现在表示成了二进制,所以不能用。
已经排好序,所以偶数奇数交替,下标奇偶与数字奇偶一样,缺失的那个数就是不一样的那个下标值。
还有一种解法是数学方法。
*
*/
public class Finder {
    public int findMissing(int[][] numbers, int n) {
        // write code here
        //math
        /*int sum = n * (n+1) / 2;
        for(int i=0;i<n;i++){
            for(int j=0;j<numbers[i].length;j++){
                if(numbers[i][j] == 1){
                    sum -= (int)Math.pow(2,j);
                }
            }
        }
        return sum;*/
        for(int i=0;i<n;i++){
            if(numbers[i][0] != i % 2){
                return i;
            }
        }
        return n;
    }
}

32、像素设定

题目描述
有一个单色屏幕储存在一维数组中,其中数组的每个元素代表连续的8位的像素的值,请实现一个函数,将第x到第y个像素涂上颜色(像素标号从零开始),并尝试尽量使用最快的办法。
给定表示屏幕的数组screen(数组中的每个元素代表连续的8个像素,且从左至右的像素分别对应元素的二进制的从低到高位),以及int x,int y,意义如题意所述,保证输入数据合法。请返回涂色后的新的屏幕数组。

测试样例:
[0,0,0,0,0,0],0,47
返回:[255,255,255,255,255,255]

import java.util.*;

public class Render {
    public int[] renderPixel(int[] screen, int x, int y) {
        // write code here
        /*int low = x / 8;
        int hi = y / 8;
        int value = 0;
        int count;
        int i;
        String binaryString;
        if(low == hi){//如果在同一个框格
            value = screen[low];
            binaryString = new StringBuilder(Integer.toBinaryString(value)).reverse().toString();
            while(x <= y){
                i = x%8;
                if(i >= binaryString.length() || binaryString.charAt(i) == '0'){
                     value += (int)Math.pow(2,i);
                }
                x++;
            }
            screen[low] = value;
        }else{
            value = screen[low]; 
            binaryString = new StringBuilder(Integer.toBinaryString(value)).reverse().toString();
            i = x%8;
            while(i < 8){
                if(i >= binaryString.length() || binaryString.charAt(i) == '0'){
                    value += (int)Math.pow(2,i);
                }
                i++;
            }
            screen[low]=value;
            
            low++;
            while(low < hi){//如果不在同一个框格
                screen[low++] = 255;
            }
            
            
            value = screen[low];
            binaryString = new StringBuilder(Integer.toBinaryString(value)).reverse().toString();
            count = 0;
            while(count < (y%8 + 1)){
                if(count >= binaryString.length() || binaryString.charAt(count) == '0'){
                    value += (int)Math.pow(2,count);
                }
                count++;
            }
            screen[low] = value;
        }
        return screen;*/
        
        int arrIndex,bitIndex;
        for(int i=x;i<=y;i++){
            arrIndex = i/8;
            bitIndex = i%8;
            screen[arrIndex] |= (1<<bitIndex);
        }
        return screen;
    }
}

33、碰撞的蚂蚁

题目描述
在n个顶点的多边形上有n只蚂蚁,这些蚂蚁同时开始沿着多边形的边爬行,请求出这些蚂蚁相撞的概率。(这里的相撞是指存在任意两只蚂蚁会相撞)
给定一个int n(3<=n<=10000),代表n边形和n只蚂蚁,请返回一个double,为相撞的概率。

测试样例:
3
返回:0.75

import java.util.*;

public class Ants {
    public double antsCollision(int n) {
        // write code here
        return 1-1.0/Math.pow(2,n-1);
    }
}

34、判断直线相交

题目描述
给定直角坐标系上的两条直线,确定这两条直线会不会相交。
线段以斜率和截距的形式给出,即double s1,double s2,double y1,double y2,分别代表直线1和2的斜率(即s1,s2)和截距(即y1,y2),请返回一个bool,代表给定的两条直线是否相交。这里两直线重合也认为相交。

测试样例:
3.14,3.14,1,2
返回:false

import java.util.*;

public class CrossLine {
    public boolean checkCrossLine(double s1, double s2, double y1, double y2) {
        // write code here
        return !(s1 == s2 && y1 != y2);
    }
}

35、加法运算替代

题目描述
请编写一个方法,实现整数的乘法、减法和除法运算(这里的除指整除)。只允许使用加号。
给定两个正整数int a,int b,同时给定一个int type代表运算的类型,1为求a * b,0为求a / b,-1为求a - b。请返回计算的结果,保证数据合法且结果一定在int范围内。

测试样例:
1,2,1
返回:2

import java.util.*;

public class AddSubstitution {
    
    public int calc(int a, int b, int type) {
        // write code here
        int result = 0;
        if(type == 1){
            for(int i=0;i<b;i++){
                result += a;
            }
        }
        else if(type == 0){
            while(a >= b){
                result++;
                a = a + ~b + 1;
            }
        }
        else if(type == -1){
            result = a + ~b + 1;
        }
        return result;
    }
}

36、平分的直线

题目描述
在二维平面上,有两个正方形,请找出一条直线,能够将这两个正方形对半分。假定正方形的上下两条边与x轴平行。

给定两个vecotrA和B,分别为两个正方形的四个顶点。请返回一个vector,代表所求的平分直线的斜率和截距,保证斜率存在。

测试样例:
[(0,0),(0,1),(1,1),(1,0)],[(1,0),(1,1),(2,0),(2,1)]
返回:[0.0,0.5]

import java.util.*;

/*
public class Point {
    int x;
    int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public Point() {
        this.x = 0;
        this.y = 0;
    }
}*/
public class Bipartition {
    class pointComparator implements Comparator<Point>{
        @Override
        public int compare(Point a,Point b){
            if(a.x != b.x){
                return a.x-b.x;
            }else{
                return a.y-b.y;
            }
        }
    }
    public double[] getBipartition(Point[] A, Point[] B) {
        // write code here
        Arrays.sort(A,new pointComparator());
        Arrays.sort(B,new pointComparator());
        double AOx = (A[0].x + A[3].x) / 2.0;
        double AOy = (A[0].y + A[3].y) / 2.0;
        double BOx = (B[0].x + B[3].x) / 2.0;
        double BOy = (B[0].y + B[3].y) / 2.0;
        double[] line = new double[2];
        line[0] = (BOy - AOy) / (BOx - AOx);
        line[1] = BOy - line[0]*BOx;
        return line;
    }
}

37、穿最多的直线

题目描述
在二维平面上,有一些点,请找出经过点数最多的那条线。

给定一个点集vectorp和点集的大小n,没有两个点的横坐标相等的情况,请返回一个vector,代表经过点数最多的那条直线的斜率和截距。

import java.util.*;

/*
public class Point {
    int x;
    int y;
    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public Point() {
        this.x = 0;
        this.y = 0;
    }
}*/
public class DenseLine {
    class line{
        double k;
        double b;
        public line(double k,double b){
            this.k = k;
            this.b = b;
        }
        @Override
        public boolean equals(Object obj){
            if (obj == this) return true;
            if (obj == null) return false;
            if (obj.getClass() != this.getClass()) return false;
            line that = (line) obj;
            return (this.k == that.k) && (this.b == that.b);
        }
        @Override
        public int hashCode(){
            int hash = 1;
            hash = 31*hash + ((Double) k).hashCode();
            hash = 31*hash + ((Double) b).hashCode();
            return hash;
        }
    }
    public double[] getLine(Point[] p, int n) {
        // write code here
        Map<line,Integer> hm = new HashMap();
        double k,b;
        int cnt;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                k = (p[i].y-p[j].y) / (p[i].x-p[j].x);
                b = p[i].y-k*p[i].x;
                line l = new line(k,b);
                hm.put(l,hm.getOrDefault(l,0)+1);
            }
        }
        int max = 0;
        line ans = new line(0,0);
        for(line l:hm.keySet()){
            if(hm.get(l) > max){
                ans = l;
            }
        }
        return new double[]{ans.k,ans.b};
        
    }
}

38、第k个数

题目描述
有一些数的素因子只有3、5、7,请设计一个算法,找出其中的第k个数。
给定一个数int k,请返回第k个数。保证k小于等于100。

测试样例:
3
返回:7

import java.util.*;

public class KthNumber {
    public int findKth(int k) {
        // write code here
        int[] uglyNum = new int[k+1];
        int m3 = 0,m5 = 0,m7 = 0;
        //note: 1 is not included
        uglyNum[0] = 1;
        for(int i=1;i<=k;i++){
            int min = Math.min(uglyNum[m3]*3, Math.min(uglyNum[m5]*5,
            uglyNum[m7]*7));
            uglyNum[i] = min;
            //update the weight of 3、5、7
            if(min == uglyNum[m3] * 3) m3++;
            if(min == uglyNum[m5] * 5) m5++;
            if(min == uglyNum[m7] * 7) m7++;
        }
        return uglyNum[k];
    }
}

39、上楼梯

题目描述
有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶、3阶。请实现一个方法,计算小孩有多少种上楼的方式。为了防止溢出,请将结果Mod 1000000007

给定一个正整数int n,请返回一个数,代表上楼的方式数。保证n小于等于100000。

测试样例1:
1
返回:1
测试样例2:
3
返回:4
测试样例3:
4
返回:7

import java.util.*;

public class GoUpstairs {
    public int countWays(int n) {
        // write code here
        int[] count = new int[n+1];
        count[0]=1;
        count[1]=1;
        count[2]=2;
        for(int i=3;i<=n;i++){
            count[i] = ((count[i-3]+count[i-2]) % 1000000007 +count[i-1]) % 1000000007;
        }
        return count[n];
    }
}

40、机器人走方格I

题目描述
有一个XxY的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。请设计一个算法,计算机器人有多少种走法。
给定两个正整数int x,int y,请返回机器人的走法数目。保证x+y小于等于12。

测试样例:
2,2
返回:2

import java.util.*;

public class Robot {
    public int countWays(int x, int y) {
        // write code here
        int[][] path = new int[x][y];
        for(int i = 0; i < x; i++){
            for(int j = 0; j < y; j++){
                if(i == 0 || j == 0){
                    path[i][j] = 1;
                }
                else{
                    path[i][j] = path[i-1][j] + path[i][j-1];
                }
            }
        }
        return path[x-1][y-1];
    }
}

41、机器人走方格II

题目描述
有一个XxY的网格,一个机器人只能走格点且只能向右或向下走,要从左上角走到右下角。请设计一个算法,计算机器人有多少种走法。注意这次的网格中有些障碍点是不能走的。
给定一个int[][] map(C++ 中为vector >),表示网格图,若map[i][j]为1则说明该点不是障碍点,否则则为障碍。另外给定int x,int y,表示网格的大小。请返回机器人从(0,0)走到(x - 1,y - 1)的走法数,为了防止溢出,请将结果Mod 1000000007。保证x和y均小于等于50

import java.util.*;

public class Robot {
    public int countWays(int[][] map, int x, int y) {
        // write code here
        int[][] path = new int[x][y];
        if(map[0][0] == 0) return 0;
        else path[0][0] = 1;
        for(int i=0;i<x;i++){
            for(int j=0;j<y;j++){
                if(i == 0 && j == 0) {
                    continue;
                }
                if(map[i][j] == 0){
                    path[i][j] = 0;
                }else{
                  if(i == 0){
                    path[i][j] = path[i][j-1];
                  }
                  else if(j == 0){
                    path[i][j] = path[i-1][j];
                  }
                  else{
                    path[i][j] = (path[i][j-1] + path[i-1][j]) % 1000000007; 
                  }
                }
            }
        }
        return path[x-1][y-1];
    }
}

42、魔术索引I

题目描述
在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个升序数组,元素值各不相同,编写一个方法,判断在数组A中是否存在魔术索引。请思考一种复杂度优于o(n)的方法。
给定一个int数组A和int n代表数组大小,请返回一个bool,代表是否存在魔术索引。

测试样例:
[1,2,3,4,5]
返回:false

import java.util.*;

public class MagicIndex {
    public boolean findMagicIndex(int[] A, int n) {
        // write code here
        int i = 0;
        while(i < n){
            if(A[i] == i) return true;
            else if(A[i] < i) i++;
            else{
                return false;
            }
        }
        return false;
    }
}

43、魔术索引II

题目描述
在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个不下降序列,元素值可能相同,编写一个方法,判断在数组A中是否存在魔术索引。请思考一种复杂度优于o(n)的方法。
给定一个int数组A和int n代表数组大小,请返回一个bool,代表是否存在魔术索引。

测试样例:
[1,1,3,4,5]
返回:true

import java.util.*;

public class MagicIndex {
    public boolean findMagicIndex(int[] A, int n) {
        // write code here
        int i = 0;
        while(i < n){
            if(A[i] == i) return true;
            else if(A[i] < i) i++;
            else{
                i = A[i];
            }
        }
        return false;
    }
}

44、集合的子集

题目描述
请编写一个方法,返回某集合的所有非空子集。
给定一个int数组A和数组的大小int n,请返回A的所有非空子集。保证A的元素个数小于等于20,且元素互异。各子集内部从大到小排序,子集之间字典逆序排序,见样例。

测试样例:
[123,456,789]
返回:{[789,456,123],[789,456],[789,123],[789],[456 123],[456],[123]}

import java.util.*;
/**
问题是我反过来给出代码,你能正确人工写出样例的运行结果吗?第11行的位置将很大影响运行的结果
*/
public class Subset {
    private void backtrack(ArrayList<Integer> list,int[] nums,int start,
             ArrayList<ArrayList<Integer>> ans){
        for(int i=start;i>=0;i--){
            list.add(nums[i]);
            backtrack(list,nums,i-1,ans);
            ans.add(new ArrayList(list));
            list.remove(list.size()-1);
        }
    }
    
    public ArrayList<ArrayList<Integer>> getSubsets(int[] A, int n) {
        // write code here
        Arrays.sort(A);
        ArrayList<ArrayList<Integer>> ans = new ArrayList<ArrayList<Integer>>();
        backtrack(new ArrayList(),A,n-1,ans);
        return ans;
    }
    
}

45、字符串排列

题目描述
编写一个方法,确定某字符串的所有排列组合。
给定一个string A和一个int n,代表字符串和其长度,请返回所有该字符串字符的排列,保证字符串长度小于等于11且字符串中字符均为大写英文字符,排列中的字符串按字典序从大到小排序。(不合并重复字符串)

测试样例:
“ABC”
返回:[“CBA”,“CAB”,“BCA”,“BAC”,“ACB”,“ABC”]

import java.util.*;

public class Permutation {
    private void dfs(char[] arr,char[] cur,int[] visit,int n,ArrayList<String> ans){
        if(n == arr.length){
            ans.add(String.valueOf(cur));
        }
        for(int i=arr.length-1;i>=0;i--){
            if(visit[i] == 0){
                visit[i] = 1;
                cur[n] = arr[i];
                dfs(arr,cur,visit,n+1,ans);
                visit[i] = 0;
            }
        }
    }
    
    public ArrayList<String> getPermutation(String A) {
        // write code here
        if(A == null || A.length() == 0) return null;
        char[] arr = A.toCharArray();
        Arrays.sort(arr);
        char[] curr = new char[arr.length];
        int[] visit = new int[arr.length];
        ArrayList<String> ans = new ArrayList();
        dfs(arr,curr,visit,0,ans);
        Collections.sort(ans,(s1,s2)->{
            return s2.compareTo(s1);
        });
        return ans;
    }
}

46、合法括号序列判断

题目描述
对于一个字符串,请设计一个算法,判断其是否为一个合法的括号串。
给定一个字符串A和它的长度n,请返回一个bool值代表它是否为一个合法的括号串。

测试样例:
“(()())”,6
返回:true
测试样例:
“()a()()”,7
返回:false
测试样例:
“()(()()”,7
返回:false

import java.util.*;

public class Parenthesis {
    public boolean chkParenthesis(String A, int n) {
        // write code here
        String B;
        do{
            B = A;
            A = A.replaceAll("\\(\\)","");
            if(B.length() == A.length()) return false;
        }while(A.length() != 0);
        return true;
    }
}

47、洪水

题目描述
在一个nxm矩阵形状的城市里爆发了洪水,洪水从(0,0)的格子流到这个城市,在这个矩阵中有的格子有一些建筑,洪水只能在没有建筑的格子流动。请返回洪水流到(n - 1,m - 1)的最早时间(洪水只能从一个格子流到其相邻的格子且洪水单位时间能从一个格子流到相邻格子)。
给定一个矩阵map表示城市,其中map[i][j]表示坐标为(i,j)的格子,值为1代表该格子有建筑,0代表没有建筑。同时给定矩阵的大小n和m(n和m均小于等于100),请返回流到(n - 1,m - 1)的最早时间。保证洪水一定能流到终点。

import java.util.*;

public class Flood {
/*    class Flowing{
        int x;
        int y;
        int time;
        public Flowing(int x,int y,int time){
            this.x = x;
            this.y = y;
            this.time = time;
        }
    }
    
    public int floodFill(int[][] map, int n, int m) {
        // write code here
       Queue<Flowing> q = new LinkedList();
       q.offer(new Flowing(0,0,0));
       map[0][0] = -1;
       int i,j,time;
       while(!q.isEmpty()){
           Flowing f = q.poll();
           i = f.x;
           j = f.y;
           time = f.time;
           if(i == n-1 && j == m-1) return time;
           
           if(i - 1 >= 0 && map[i-1][j] == 0){
               Flowing l = new Flowing(i-1,j,time+1);
               q.offer(l);
               map[i-1][j] = -1;
           }
           if(i + 1 < n && map[i+1][j] == 0){
               Flowing r = new Flowing(i+1,j,time+1);
               q.offer(r);
               map[i+1][j] = -1;
           }
           if(j - 1 >= 0 && map[i][j-1] == 0){
               Flowing u = new Flowing(i,j-1,time+1);
               q.offer(u);
               map[i][j-1] = -1;
           }
           if(j + 1 < m && map[i][j+1] == 0){
               Flowing d = new Flowing(i,j+1,time+1);
               q.offer(d);
               map[i][j+1] = -1;
           }
       }
        return 0;
    }
    */
    public int floodFill(int[][] map, int n, int m) {
        return n+m-2;
    }
}

48、硬币表示

题目描述
有数量不限的硬币,币值为25分、10分、5分和1分,请编写代码计算n分有几种表示法。
给定一个int n,请返回n分有几种表示法。保证n小于等于100000,为了防止溢出,请将答案Mod 1000000007。

测试样例:
6
返回:2

import java.util.*;
/**
跟台阶上法思路不一样,还有一道最少硬币数的题,跟那道题思路接近
只有1分;有1分和5分,此时又有新表示,更新数组;有1分、5分和10分......
*/
public class Coins {
    public int countWays(int n) {
        // write code here
        int[] count = new int[n+1];
        int[] coins = new int[]{1,5,10,25};
        count[0] = 1;
        for(int i=0;i<4;i++){            
            for(int j=coins[i];j<=n;j++){
                count[j] += count[j-coins[i]];
                if(count[j]>1000000007) count[j] = count[j] % 1000000007;
            }
        }
        return count[n];
    }
}

49、n皇后问题

题目描述
请设计一种算法,解决著名的n皇后问题。这里的n皇后问题指在一个nxn的棋盘上放置n个棋子,使得每行每列和每条对角线上都只有一个棋子,求其摆放的方法数。
给定一个int n,请返回方法数,保证n小于等于15

测试样例:
1
返回:1

import java.util.*;

public class Queens {
    //假设第i个皇后放在第i行,行上无冲突
    //pos[i]表示第i个皇后放置在那一列
    //isplace方法用来判断第k个皇后的位置是否正确
    private boolean isplace(int[] pos,int k){
        for(int i=1;i<k;i++){
            if(pos[i] == pos[k] || Math.abs(i-k) == Math.abs(pos[i]-pos[k])){
                return false;
            }
        }
        return true;
    }
    public int nQueens(int n) {
        // write code here
        int[] pos = new int[n+1];
        //j表示第j个皇后
        int j=1;
        int count = 0;
        while(j >= 1){//j=0时表示所有的情况都已考虑完成
            pos[j]++;
            while(pos[j] <= n && !isplace(pos,j)){
                pos[j]++;
            }
            if(pos[j] <= n && j == n){
                count++;
                //可打印皇后所在列的值
            }
            if(pos[j] <= n && j < n){
                j++;
            }
            else{//所有的列值都试过,还是没有可放的位置。回溯。
                pos[j] = 0;
                //考虑上一个皇后
                j--;
            }
        }
        return count;
    }
}

50、堆箱子

题目描述
有一堆箱子,每个箱子宽为wi,长为di,高为hi,现在需要将箱子都堆起来,而且为了使堆起来的箱子不倒,上面的箱子的宽度和长度必须小于下面的箱子。请实现一个方法,求出能堆出的最高的高度,这里的高度即堆起来的所有箱子的高度之和。
给定三个int数组w,l,h,分别表示每个箱子宽、长和高,同时给定箱子的数目n。请返回能堆成的最高的高度。保证n小于等于500。

测试样例:
[1,1,1],[1,1,1],[1,1,1]
返回:1

import java.util.*;
/**
跟叠罗汉又很像,举一反三
*/
public class Box {
    private void swap(int[] arr,int i,int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public int getHeight(int[] w, int[] l, int[] h, int n) {
        // write code here
        for(int i=0;i<n;i++){
            for(int j=0;j<n-i-1;j++){
                if(w[j] > w[j+1]){
                    swap(w,j,j+1);
                    swap(l,j,j+1);
                    swap(h,j,j+1);
                }
            }
        }
        int[] maxheight = new int[n];
        maxheight[0] = h[0];
        int ans = maxheight[0];
        int tmp;
        for(int i=1;i<n;i++){
            tmp = h[i];
            for(int j=0;j<i;j++){
                if(w[j] < w[i] && l[j] < l[i]){
                    tmp = Math.max(tmp,maxheight[j]+h[i]);
                }
            }
            maxheight[i] = tmp;
            ans = Math.max(maxheight[i],ans);
        }
        return ans;
    }
}

51、约瑟夫问题I

题目描述
约瑟夫问题是一个非常著名的趣题,即由n个人坐成一圈,按顺时针由1开始给他们编号。然后由第一个人开始报数,数到m的人出局。现在需要求的是最后一个出局的人的编号。
给定两个int n和m,代表游戏的人数。请返回最后一个出局的人的编号。保证n和m小于等于1000。

测试样例:
5 3
返回:4

import java.util.*;

public class Joseph {
    public int getResult(int n, int m) {
        // write code here
        if(n<1||m<1)
            return -1;
        int s=0;
        for(int i=2;i<=n;i++)
            s=(s+m)%i;
        return s+1;
    }
}

52、约瑟夫问题II

题目描述
约瑟夫问题是一个著名的趣题。这里我们稍稍修改一下规则。有n个人站成一列。并从头到尾给他们编号,第一个人编号为1。然后从头开始报数,第一轮依次报1,2,1,2…然后报到2的人出局。接着第二轮再从上一轮最后一个报数的人开始依次报1,2,3,1,2,3…报到2,3的人出局。以此类推直到剩下以后一个人。现在需要求的即是这个人的编号。
给定一个int n,代表游戏的人数。请返回最后一个人的编号

测试样例:
5
返回:5

import java.util.*;

public class Joseph {
    public int getResult(int n) {
        // write code here
        if(n < 1)
            return -1;
        LinkedList<Integer> list = new LinkedList<Integer>();
        int max = 2, curr = 0, index=0;
        for(int i = 1;i <= n;i++){
            list.add(i);
        }
        while(list.size() > 1){
            index = 0;
            while( list.size() > 1 && index < list.size()){
                curr = (curr+1) % max;
                if(curr != 1){
                    list.remove(index);
                }else{
                    index++;
                }
            }
            max++;
            curr = 0;
            if(list.size() > 1){
                int last = list.removeLast();
                list.addFirst(last);
            }
        }
        return list.pop();
    }
}

53、变位词排序

题目描述
请编写一个方法,对一个字符串数组进行排序,将所有变位词合并,保留其字典序最小的一个串。这里的变位词指变换其字母顺序所构成的新的词或短语。例如"triangle"和"integral"就是变位词。
给定一个string的数组str和数组大小int n,请返回排序合并后的数组。保证字符串串长小于等于20,数组大小小于等于300。

测试样例:
[“ab”,“ba”,“abc”,“cba”]
返回:[“ab”,“abc”]

import java.util.*;

public class SortString {
    private String getKey(String s){
        char[] arr = s.toCharArray();
        Arrays.sort(arr);
        return String.valueOf(arr);
    }
    
    public ArrayList<String> sortStrings(String[] str, int n) {
        // write code here
        Arrays.sort(str);
        Map<String,String> hm = new HashMap();
        ArrayList<String> ans;
        for(String s:str){
            String key = getKey(s);
            if(!hm.containsKey(key)){
                hm.put(key,s);
            }
        }
        ans = new ArrayList(hm.values());
        Collections.sort(ans);
        return ans;
    }
}

54、元素查找

题目描述
有一个排过序的数组,包含n个整数,但是这个数组向左进行了一定长度的移位,例如,原数组为[1,2,3,4,5,6],向左移位5个位置即变成了[6,1,2,3,4,5],现在对于移位后的数组,需要查找某个元素的位置。请设计一个复杂度为log级别的算法完成这个任务。
给定一个int数组A,为移位后的数组,同时给定数组大小n和需要查找的元素的值x,请返回x的位置(位置从零开始)。保证数组中元素互异。

测试样例:
[6,1,2,3,4,5],6,6
返回:0

import java.util.*;

public class Finder {
    public int findElement(int[] nums, int n, int target) {
        // write code here
        int lo = 0;
        int hi = nums.length-1;
        if(hi < 0) return -1;
        while(lo < hi){
            int mid = (lo+hi) / 2;
            if(nums[mid] == target) return mid;
            //找有序段
            if(nums[lo] <= nums[mid]){
                if(target >= nums[lo] && target < nums[mid]){
                    hi = mid - 1;
                }
                else{
                    lo = mid + 1;
                }
            } else {
                if(target > nums[mid] && target <= nums[hi]){
                    lo = mid + 1;
                } else{
                    hi = mid - 1;
                }
            }
        }
        return nums[lo] == target ? lo : -1;
    }
}

55、找出字符串

题目描述
有一个排过序的字符串数组,但是其中有插入了一些空字符串,请设计一个算法,找出给定字符串的位置。算法的查找部分的复杂度应该为log级别。
给定一个string数组str,同时给定数组大小n和需要查找的string x,请返回该串的位置(位置从零开始)。

测试样例:
[“a”,“b”,"",“c”,"",“d”],6,“c”
返回:3

import java.util.*;
/**

*/
public class Finder {
    public int findString(String[] str, int n, String x) {
        // write code here
        int lo = 0,hi = n-1,mid,p;
        while(lo <= hi){
            mid = lo + (hi-lo) / 2;
            if("".equals(str[mid])){
                p = mid;
                while(p <= hi && "".equals(str[p])){
                    p++;
                }
                if(p <= hi && x.compareTo(str[p]) == 0) return p;
                else if(x.compareTo(str[p]) > 0){
                    lo = p+1;
                }
                else{
                    p = mid-1;
                    while(p >= 0 && "".equals(str[p])){
                        p--;
                    }
                    if(p >= 0 && x.compareTo(str[p]) == 0) return p;
                    else{
                        hi = p-1;
                    }
                }
            }else{
                if(x.equals(str[mid])) return mid;
                else if(x.compareTo(str[mid]) > 0){
                    lo = mid + 1;
                }
                else{
                    hi = mid - 1;
                }
            }
        }
        return -1;
        
    }
}

56、矩阵元素查询

题目描述
有一个NxM的整数矩阵,矩阵的行和列都是从小到大有序的。请设计一个高效的查找算法,查找矩阵中元素x的位置。
给定一个int有序矩阵mat,同时给定矩阵的大小n和m以及需要查找的元素x,请返回一个二元数组,代表该元素的行号和列号(均从零开始)。保证元素互异。

测试样例:
[[1,2,3],[4,5,6]],2,3,6
返回:[1,2]

import java.util.*;

public class Finder {
    public int[] findElement(int[][] matrix, int m, int n, int target) {
        // write code here
        for(int i=0;i<m;i++){
            if( target >= matrix[i][0] && target <= matrix[i][n-1]){
                int low = 0,high = n-1;
                while(low <= high){
                   int mid = (low + high) / 2;
                   if(matrix[i][mid] == target) return new int[]{i,mid};
                   else if(matrix[i][mid] > target) high = mid -1;
                   else low = mid + 1;
                }               
            }
        }
        return new int[]{-1,-1};
    }
}

57、叠罗汉I

题目描述
叠罗汉是一个著名的游戏,游戏中一个人要站在另一个人的肩膀上。同时我们应该让下面的人比上面的人更高一点。已知参加游戏的每个人的身高,请编写代码计算通过选择参与游戏的人,我们最多能叠多少个人。注意这里的人都是先后到的,意味着参加游戏的人的先后顺序与原序列中的顺序应该一致。
给定一个int数组men,代表依次来的每个人的身高。同时给定总人数n,请返回最多能叠的人数。保证n小于等于500。

测试样例:
[1,6,2,5,3,4],6
返回:4

import java.util.*;

public class Stack {
    public int getHeight(int[] nums, int len) {
        // write code here
        if(len == 0) return 0;
        int[] dp = new int[len];
        int max = 1;
        for(int i=0;i<len;i++){
            int tmp = 1;
            for(int j=0;j<i;j++){
               if(nums[i] > nums[j] && dp[j] + 1 > tmp){
                   tmp = dp[j] + 1;
               }
            }
            dp[i] = tmp;
            max = Math.max(tmp,max);
        }
        return max;
    }
}

58、叠罗汉II

题目描述
叠罗汉是一个著名的游戏,游戏中一个人要站在另一个人的肩膀上。为了使叠成的罗汉更稳固,我们应该让上面的人比下面的人更轻一点。现在一个马戏团要表演这个节目,为了视觉效果,我们还要求下面的人的身高比上面的人高。请编写一个算法,计算最多能叠多少人,注意这里所有演员都同时出现。
给定一个二维int的数组actors,每个元素有两个值,分别代表一个演员的身高和体重。同时给定演员总数n,请返回最多能叠的人数。保证总人数小于等于500。

测试样例:
[[1,2],[3,4],[5,6],[7,8]],4
返回:4

import java.util.*;
/**
还记得two sum,three sum, four sum吗?
这个题思路也一样,是最长递增子序列的增强版,先对身高排序再求体重的递增子序列长度
*/
public class Stack {
    public int getHeight(int[][] actors, int n) {
        // write code here
        Arrays.sort(actors,(int[] a1,int[] a2)->{
            return a1[0] - a2[0];
        });
        int[] dp = new int[n];
        int max = 1;
        for(int i=0;i<n;i++){
            int tmp = 1;
            for(int j=0;j<i;j++){
                if(actors[i][1] > actors[j][1] && dp[j] + 1 > tmp){
                    tmp = dp[j] + 1;
                }
            }
            dp[i] = tmp;
            max = Math.max(dp[i],max);
        }
        return max;
    }
}

59、维护x的秩

题目描述
现在我们要读入一串数,同时要求在读入每个数的时候算出它的秩,即在当前数组中小于等于它的数的个数(不包括它自身),请设计一个高效的数据结构和算法来实现这个功能。
给定一个int数组A,同时给定它的大小n,请返回一个int数组,元素为每次加入的数的秩。保证数组大小小于等于5000。

测试样例:
[1,2,3,4,5,6,7],7
返回:[0,1,2,3,4,5,6]

import java.util.*;
/*
比二叉查找树多维护一个变量:左节点包括自己数目
*/

public class Rank {
    class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        int count;//节点左子树节点包含自己的个数
        public TreeNode(int val){
            this.val = val;
        }
    }
    
    private TreeNode insertNode(TreeNode root,int x){
        if(root == null){
            TreeNode t = new TreeNode(x);
            root = t;
            root.count++;
        }
        else if(root.val > x){
            root.left = insertNode(root.left,x);
            root.count++;
        }
        else if(root.val < x){
            root.right = insertNode(root.right,x);

        }
        else if(root.val == x){
            root.count++;
        }
        return root;
    }
    private int getCount(TreeNode root,int x){
        if(root == null){
            return 0;
        }
        if(x == root.val){
            return root.count;
        }
        else if(x < root.val){
            return getCount(root.left,x);
        }
        else if(x > root.val){
            return root.count + getCount(root.right,x);
        }
        return 0;
    }
    public int[] getRankOfNumber(int[] A, int n) {
        // write code here
        TreeNode root = null;
        int tmp;
        for(int i=0;i<n;i++){
            tmp = A[i];
            A[i] = getCount(root,tmp);
            root = insertNode(root,tmp);
        }
        return A;
    }
}

60、数组中的逆序对

题目描述
有一组数,对于其中任意两个数组,若前面一个大于后面一个数字,则这两个数字组成一个逆序对。请设计一个高效的算法,计算给定数组中的逆序对个数。
给定一个int数组A和它的大小n,请返回A中的逆序对个数。保证n小于等于5000。

测试样例:
[1,2,3,4,5,6,7,0],8
返回:7

import java.util.*;

public class AntiOrder {
    private int mergeSort(int [] a,int []b,int start,int end){
        if(end - start > 1){ //数组中至少2个数
            int mid = (start + end) / 2;
            int p = start , q = mid , i = start;
            int ans = 0;
            ans = ans + mergeSort(a,b,start,mid);
            ans = ans + mergeSort(a,b,mid,end);
            
            while(p < mid || q < end){
                if(q >= end || (p < mid && a[p] <= a[q])){ //直接复制或为正序
                    b[i++] = a[p++];
                }
                else{
                    ans = ans + mid - p;
                    b[i++] = a[q++];
                }
            }
            for(i=start;i<end;i++)
                a[i] = b[i];
            return ans;
        }
        return 0;
    }
    public int count(int[] A, int n) {
        // write code here
        int[] B = new int[n];
        return mergeSort(A,B,0,n);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wsws100

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值