难得的算法题

来自牛客: https://www.nowcoder.com/practice/a0c19f3489774fe693d71490ce83b648?tpId=8&tqId=11068&rp=2&ru=%2Fta%2Fcracking-the-coding-interview&qru=%2Fta%2Fcracking-the-coding-interview%2Fquestion-ranking&tPage=4

下一个较大元素

测试样例:

[11,13,10,5,12,21,3],7
返回:[13,21,12,12,21,-1,-1]
import java.util.*;

public class NextElement {
    public int[] findNext(int[] a, int n) {
        // write code here
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        ArrayList<Integer> res = new ArrayList<>();
        for(int i = n-1; i >= 0; i--) {
            Integer tmp = stack.peek();
            while (tmp != null && tmp != -1 && tmp <= a[i]) {
                stack.pop();
                tmp = stack.peek();
            }
            res.add(0,tmp == null ? -1 : tmp);
            stack.push(a[i]);
        }
        return res.stream().mapToInt(i -> Integer.valueOf(i)).toArray();
    }
}

最大连续数列和

对于一个有正有负的整数数组,请找出总和最大的连续数列。

给定一个int数组A和数组大小n,请返回最大的连续数列的和。保证n的大小小于等于3000。

import java.util.*;

public class MaxSum {
    public int getMaxSum(int[] a, int n) {
        // write code here
        int[] dp = new int[n];
        int res = a[0];
        for (int i = 0; i < n; i++) {
            if (i == 0) dp[i] = a[0];
            else dp[i] = Math.max(dp[i-1]+a[i], a[i]);
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

珠玑妙算

我们现在有四个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,可能的情况为RGGB(槽1为红色,槽2、3为绿色,槽4为蓝色),作为玩家,你需要试图猜出颜色的组合。比如,你可能猜YRGB。要是你猜对了某个槽的颜色,则算一次“猜中”。要是只是猜对了颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。

给定两个string Aguess。分别表示颜色组合,和一个猜测。请返回一个int数组,第一个元素为猜中的次数,第二个元素为伪猜中的次数。

import java.util.*;

public class Result {
    public int[] calcResult(String a, String guess) {
        // write code here
        //计算猜中的个数
        int right = 0;
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0 ; i < a.length(); i++) {
            if (a.charAt(i) == guess.charAt(i)) {
                 right++;
            }
            Integer tmp = map.get(a.charAt(i));
            if (tmp == null) {
                map.put(a.charAt(i),1);
            }else {
                map.put(a.charAt(i),tmp+1);
            }
        }
        //计算伪猜中的个数
        int halfRight = 0;
        for (int i = 0; i < guess.length(); i++) {
            Integer tmp = map.get(guess.charAt(i));
            if (tmp != null && tmp != 0) {
                halfRight++;
                tmp--;
                map.put(guess.charAt(i), tmp);
            }
        }
        //去除伪猜中中猜中的个数
        halfRight -= right;
        return new int[]{right, halfRight};
    }
}

数组中的逆序对

有一组数,对于其中任意两个数组,若前面一个大于后面一个数字,则这两个数字组成一个逆序对。请设计一个高效的算法,计算给定数组中的逆序对个数。

给定一个int数组A和它的大小n,请返回A中的逆序对个数。保证n小于等于5000。

思路: 先把数组分割成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目

import java.util.*;

public class AntiOrder {
    public int count(int[] A, int n) {
        // write code here
       if (A == null || n == 0) return 0;
        return mergeSortRecursion(A, 0, n-1);
    }
    public int mergeSortRecursion(int[] a, int l, int r) {
        if (l == r) return 0;
        int m = l + (r-l) / 2;
        return mergeSortRecursion(a, l, m) + mergeSortRecursion(a, m+1, r) + merge(a, l, m, r);
    }
    public int merge(int[] a, int l, int m, int r) {
        int[] tmp = new int[r-l+1];
        int k = 0, i = l, j = m+1;
        int res = 0;
        while (i <= m && j <= r) {
            if (a[i] <= a[j]) {
                tmp[k++] = a[i++];
            }else {
                //关键代码 2个排序数组, 如果一个数组第一个数比第二个数组的第一个数大 则逆序对个数 = m-i+1;
                res += m-i+1;
                tmp[k++] = a[j++];
            }
        }
        while (i <= m) tmp[k++] = a[i++];
        while (j <= r) tmp[k++] = a[j++];
        for (int x = 0; x < tmp.length; x++) {
            a[l++] = tmp[x];
        }
        return res;
    }
}

叠罗汉

叠罗汉是一个著名的游戏,游戏中一个人要站在另一个人的肩膀上。为了使叠成的罗汉更稳固,我们应该让上面的人比下面的人更轻一点。现在一个马戏团要表演这个节目,为了视觉效果,我们还要求下面的人的身高比上面的人高。请编写一个算法,计算最多能叠多少人,注意这里所有演员都同时出现。

给定一个二维int的数组actors,每个元素有两个值,分别代表一个演员的身高和体重。同时给定演员总数n,请返回最多能叠的人数。保证总人数小于等于500。

import java.util.*;

public class Stack {
    public int getHeight(int[][] actors, int n) {
        // write code here
        Comparator<int[]> com = new Comparator<int[]> (){
            public int compare(int[] a, int[] b){
                //按照身高排序
                if (a[0] < b[0]) return -1;
                if (a[0] > b[0]) return 1;
                //身高相同, 按照体重排序
                if (a[1] < b[1]) return -1;
                if (a[1] > b[1]) return 1;
                return 0;
            }
        };
        Arrays.sort(actors, com);
        int[] dp = new int[n];
        dp[0] = 1;
        int res = 0;
        //当前的高度 = 前面最大高度+1
        for (int i = 1; i < n; i++) {
            int sub = 0;
            for (int j = 0; j < i; j++) {
                //体重小于i的体重
                if (actors[j][1] < actors[i][1]) {
                    sub = Math.max(dp[j], sub);
                }
            }
            dp[i] = sub+1;
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

叠罗汉简单版

叠罗汉是一个著名的游戏,游戏中一个人要站在另一个人的肩膀上。同时我们应该让下面的人比上面的人更高一点。已知参加游戏的每个人的身高,请编写代码计算通过选择参与游戏的人,我们最多能叠多少个人。注意这里的人都是先后到的,意味着参加游戏的人的先后顺序与原序列中的顺序应该一致。 

给定一个int数组men,代表依次来的每个人的身高。同时给定总人数n,请返回最多能叠的人数。保证n小于等于500。

import java.util.*;

public class Stack {
    public int getHeight(int[] men, int n) {
        // write code here
        int[] dp = new int[n];
        dp[0] = 1;
        int res = 0;
        for (int i = 1; i < n; i++) {
            int sub = 0;
            for (int j = 0; j < i; j++) {
                if (men[j] < men[i]) {
                    sub = Math.max(dp[j], sub);
                }
            }
            dp[i] = sub+1;
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}

矩阵元素的查找

有一个NxM的整数矩阵,矩阵的行和列都是从小到大有序的。请设计一个高效的查找算法,查找矩阵中元素x的位置。

给定一个int有序矩阵mat,同时给定矩阵的大小nm以及需要查找的元素x,请返回一个二元数组,代表该元素的行号和列号(均从零开始)。保证元素互异。

import java.util.*;

public class Finder {
    public int[] findElement(int[][] mat, int n, int m, int x) {
        // write code here
        // 从左下角开始二分查找
        int i = n-1, j = 0;
        while (i >= 0 && j <= m-1) {
            if (mat[i][j] == x) return new int[]{i, j};
            if (mat[i][j] > x) {
                i--;
            }else {
                j++;
            }
        }
        return null;
    }
}

旋转数组查找

有一个排过序的数组,包含n个整数,但是这个数组向左进行了一定长度的移位,例如,原数组为[1,2,3,4,5,6],向左移位5个位置即变成了[6,1,2,3,4,5],现在对于移位后的数组,需要查找某个元素的位置。请设计一个复杂度为log级别的算法完成这个任务。

给定一个int数组A,为移位后的数组,同时给定数组大小n和需要查找的元素的值x,请返回x的位置(位置从零开始)。保证数组中元素互异。

import java.util.*;

public class Finder {
    public int findElement(int[] a, int n, int x) {
        // write code here
        int l = 0, r = n-1;
        while (l <= r) {
            int m = l+(r-l)/2;
            if (a[m] == x) return m;
            if (a[l] < a[m]) {
                if (x >= a[l] && x < a[m]) {
                    r = m-1;
                }else {
                    l = m +1;
                }
            }else {
                if (x > a[m] && x <= a[r]) {
                    l = m + 1;
                }else {
                    r = m-1;
                }
            }
        }
        return -1;
    }
}

堆箱子

有一堆箱子,每个箱子宽为wi,长为di,高为hi,现在需要将箱子都堆起来,而且为了使堆起来的箱子不倒,上面的箱子的宽度和长度必须小于下面的箱子。请实现一个方法,求出能堆出的最高的高度,这里的高度即堆起来的所有箱子的高度之和。 

给定三个int数组w,l,h,分别表示每个箱子宽、长和高,同时给定箱子的数目n。请返回能堆成的最高的高度。保证n小于等于500。


//严格的最大递增子序列问题
//先按照宽度排序(或者长度排序),然后从第一个点开始找起,看看本身能达到的最大高度;
//参考代码如下;
class Box {
public:
    //交换数值;
    void swap(int& a,int& b)
    {
        int temp=a;
        a=b;
        b=temp;
    }
    int getHeight(vector<int> w, vector<int> l, vector<int> h, int n) {
        // write code here
        //step1:按照宽度排列(冒泡排序法);
        for(int i=0;i<w.size()-1;i++)
        {
            for(int j=i+1;j<w.size();j++)
            {
                if(w[j]>w[i])
                {
                    swap(w[i],w[j]);
                    swap(l[i],l[j]);
                    swap(h[i],h[j]);
                }
            }
        }
        int maxH[200] = {0}; //存放n个箱子的最大上升高度;
        maxH[0]=h[0];//第一个箱子得到的最大高度就是本身;
        int res=maxH[0];
        for(int i=1;i<n;i++)
        {
            maxH[i]=h[i];//该箱子的最小高度(至少)就是本身的高度;
            int temp=0;
            //下面这个for循环主要计算该点(前面)能够得到的最大高度;
            for(int j = 0; j < i; j++)
            {
                if(w[j]>w[i] && l[j]>l[i])
                {
                    temp=Math.max(temp, maxH[j]);
                }
            }
            //将本身的高度加上之前箱子可以得到的最大高度,得到现在的高度;
            maxH[i]+=temp;
            //该res主要不断维护最大值,不然还要在maxH数组中寻找最大值;
            res=Math.max(res, maxH[I]);
        }
        return res;
    }
};

洪水

在一个nxm矩阵形状的城市里爆发了洪水,洪水从(0,0)的格子流到这个城市,在这个矩阵中有的格子有一些建筑,洪水只能在没有建筑的格子流动。请返回洪水流到(n - 1,m - 1)的最早时间(洪水只能从一个格子流到其相邻的格子且洪水单位时间能从一个格子流到相邻格子)。 

给定一个矩阵map表示城市,其中map[i][j]表示坐标为(i,j)的格子,值为1代表该格子有建筑,0代表没有建筑。同时给定矩阵的大小nm(n和m均小于等于100),请返回流到(n - 1,m - 1)的最早时间。保证洪水一定能流到终点。


class Flood {
public:
    int floodFill(vector<vector<int> > map, int n, int m) {
        // write code here
        if(n == 0||m == 0|| map[0][0]) return 0;
        queue<int> qx,qy;
        int direction[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
        int x,y,next_x,next_y;
        int k;
        qx.push(0);qy.push(0);
        while(!qx.empty()){
            x = qx.poll();
            y = qy.poll();
            //第一次到达 就是最早的时间
            if((x == n-1 && (y == m-1){
                return map[n-1][m-1];
            }
            for(k=0;k<4;k++){
                next_x = x + direction[k][0];
                next_y = y + direction[k][1];
                if(next_x>=0 && next_x<n && next_y>=0 && next_y<m && map[next_x][next_y] == 0){
                    qx.push(next_x);qy.push(next_y);
                    map[next_x][next_y] = map[x][y] + 1;
                }
            }
        }
    }
};

合法括号序列判断

public boolean chkParenthesis(String A, int n) {
    int l = 0; //左括号数
    for (int i = 0; i < A.length(); i++) {
        char c = A.charAt(i);
        if (c == '(') {
            l++;
        } else if (c == ')') {
            if (l > 0) {
                l--;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }
 
    return l == 0;
}

字符串排列

编写一个方法,确定某字符串的所有排列组合。

给定一个string A和一个int n,代表字符串和其长度,请返回所有该字符串字符的排列

import java.util.*;

public class Permutation {
    public ArrayList<String> getPermutation(String A) {
        // write code here
        ArrayList<String> res = new ArrayList<>();
        help(res, "", A);
        return res;
    }
    private void help (ArrayList<String> res, String have, String remain) {
        if (remain.length() ==0) {
            res.add(have);
        }else {
            for (int i = 0; i < remain.length(); i++) {
                help(res, have+remain.charAt(i), remain.substring(0,i)+remain.substring(i+1));
            }
        }
    }
}

魔术索引

在数组A[0..n-1]中,有所谓的魔术索引,满足条件A[i]=i。给定一个不下降序列,编写一个方法,判断在数组A中是否存在魔术索引。请思考一种复杂度优于o(n)的方法。

给定一个int数组A和int n代表数组大小,请返回一个bool,代表是否存在魔术索引。


bool findMagicIndex(vector<int> A, int n) {
        if(n == 0) return true;
        int mid = 0,start = 0,end = n;
        while(start < end){
            mid = (start+end)/2;
            if(mid == A[mid]) return true;
            else if(mid > A[mid]) start = mid + 1;
            else end = mid ;
        }
        return false;
    }

用2个栈实现一个对列


用两个栈实现一个队列的功能?要求给出算法和思路!

<分析>:

入队:将元素进栈A

出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈;

 如果不为空,栈B直接出栈。

用两个队列实现一个栈的功能?要求给出算法和思路!

<分析>:

入栈:将元素进队列A

出栈:判断队列A中元素的个数是否为1,如果等于1,则出队列,否则将队列A中的元素出队列并放入队列B,直到队列A中的元素留下一个,然后队列A出队列,再把队列B中的元素出队列依次放入队列A中。


public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
     
    public void push(int node) {
        stack1.push(node);
    }
     
    public int pop() {
        if(stack1.empty()&&stack2.empty()){
            throw new RuntimeException("Queue is empty!");
        }
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值