算法题目集

1、来自网易:
为了找到自己满意的工作,牛牛收集了每种工作的难度和报酬。牛牛选工作的标准是在难度不超过自身能力值的情况下,牛牛选择报酬最高的工作。在牛牛选定了自己的工作后,牛牛的小伙伴们来找牛牛帮忙选工作,牛牛依然使用自己的标准来帮助小伙伴们。牛牛的小伙伴太多了,于是他只好把这个任务交给了你。
思路:按照工作难度进行排序,这里用到了Arrays.sort(),重写了compare方法。再按照dp的方法,每次比较和前一项工作获利最大的填入map。最后直接取map.floorKey()(方法调用返回的最大键小于等于key,或者null,如果不存在这样的键)

import java.util.*;
public class Main{
 ublic static void main(String[] args) {
        // TODO Auto-generated method stub
         Scanner sc=new Scanner(System.in);
         TreeMap<Integer, Integer> map=new TreeMap<>();
         int m=sc.nextInt();//工作的数量
         int n=sc.nextInt();//小伙伴的数量
         int[][] work=new int[m][2];
         for(int i=0;i<m;i++){
             work[i][0]=sc.nextInt();//工作难度
             work[i][1]=sc.nextInt();//工作获利
         }
         //按工作难度排序
         Arrays.sort(work,new Comparator<int[]>() {
             public int compare(int[] num1,int[] num2){
                 return num1[0]-num2[0];
             }
        });
         //dp使相应的工作难度获利最大,并把结果存入map中
         for(int i=1;i<m;i++){
             work[i][1]=Math.max(work[i-1][1], work[i][1]);
             map.put(work[i-1][0], work[i-1][1]);
         }
         //最后一项加入map
         map.put(work[m-1][0], work[m-1][1]);
         for(int i=0;i<n;i++){
             //根据工作难度找工作
             int d=sc.nextInt();
             Integer index=map.floorKey(d);
             if(index!=null){
                 System.out.println(map.get(index));
             }else{
                 System.out.println(0);
             }
         }
    }
}

2、题目:整数成绩最大化
给出一个整数n,将n分解为至少两个整数之和,使得这些整数的乘积最大化,输出能够获得的最大的乘积。

例如:
2=1+1,输出1;
10=3+3+4,输出36。
输入为1个整数,输出为1个整数

示例1:输入:10,输出:36

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
       //2和3单独处理
        if(n==2){
            System.out.println(1);
            return;
        }
        if(n==3){
            System.out.println(2);
            return;
        }
        System.out.println(getResult(n));
    }
    //最优化问题,尽量都分成3,不足部分就分成2
    static long getResult(int n){
        long result=1;
        while(n>4){
            result=result*3;
            n-=3;
        }
        result = result*n;
        return result; 
    }
}

3、题目:寻找合法字符串
给出一个正整数n,请给出所有的包含n个'('和n个')'的字符串,使得'('和')'可以完全匹配。
例如:
'(())()','()()()' 都是合法的;
'())()('是不合法的。
请按照字典序给出所有合法的字符串。

示例1:输入:2 输出:(()),()()

由于字符串只有左括号和右括号两种字符,而且最终结果必定是左括号3个,右括号3个,所以我们定义两个变量left和right分别表示剩余左右括号的个数,如果在某次递归时,左括号的个数大于右括号的个数,说明此时生成的字符串中右括号的个数大于左括号的个数,即会出现')('这样的非法串,所以这种情况直接返回,不继续处理。如果left和right都为0,则说明此时生成的字符串已有3个左括号和3个右括号,且字符串合法,则存入结果中后返回。如果以上两种情况都不满足,若此时left大于0,则调用递归函数,注意参数的更新,若right大于0,则调用递归函数,同样要更新参数。代码如下:

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        List<String> list=new ArrayList<>();
        DFS(n,n,"",list);
        Collections.sort(list);
        for(int i=0;i<list.size();i++){
            if(i<list.size()-1){
            System.out.print(list.get(i)+",");
            }else{
                System.out.print(list.get(i));
            }
        }
    }
    static void DFS(int left,int right,String result,List<String> list){
        if(left<0||right<0||left>right){
            return;
        }
        if(left==0&&right==0){
            list.add(result);
            return;
        }
        DFS(left-1,right,result+"(",list);
        DFS(left,right-1,result+")",list);
        
    }
}

引申:全排列的递归算法
算法思路:

(1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀);

(2)出口:如果只有一个元素的全排列,则说明已经排完,则输出数组;

(3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等到出口,出口出去后还需要还原数组;

4、Map:

Map<String,Integer> map=new Hashmap<>();
 (1)int t=map.get(str);
(2)  for(String key:map.keySet()){
             if(str.equals(key)){
                       int i=map.get(key);
                       map.put(str,i+1);
              }else{
                    map.put(str,1);
              }
     }
        

6、题目:
给定一个整型数组a (int[]),包含N个元素。判断是否这N个整数可以构造出一个 "按位与等式",即是否存在这样一个等式:将数组中的任意N-1个整数进行按位求与操作(即Java中的"&"操作),得到的结果等于剩下的那个整数,注意这N个整数在等式中均必须出现且只出现一次。举例一:给定一个数组[5,20,4],结果为:true,因为 "20 & 5 = 4"。举例二:[5,3,7,19],结果为:false,因为数组中任何三个整数按位取与,均无法等于剩下的那个整数。请按如下函数定义,写出你的程序。(注:不能使用本地IDE)

boolean isAndEqationExist(int[] a);

分析:一个重要的点是,等号右边的数字的特征:因为是求与的结果,所以必然是最小的数字。如果能分析到这个点,则只需要一次求与的尝试,即可得出结论。
即每次都遍历找最小值,同时求它们相与的结果,(一个数与自己是不变的),结果等于最小值,则返回true;

boolean isAndEqationExist(int[] a) {
    if (a == null || a.length == 0)
        return false;
    int s = a[0];
    int min = s;
    for (int i = 1; i < a.length; i++) {
        s &= a[i];
        if (min > a[i])
            min = a[i];
    } 
    if (min == s)
        return true;
    return false;  
}

7、
动态规划!!!
当求解的问题满足以下两个条件时, 就应该使用动态规划:
(1)主问题的答案 包含了 可分解的子问题答案 (也就是说,问题可以被递归的思想求解)
(2)递归求解时, 很多子问题的答案会被多次重复利用

动态规划的本质思想就是递归, 但如果直接应用递归方法, 子问题的答案会被重复计算产生浪费, 同时递归更加耗费栈内存(具体为什么更加消耗栈内存, 需要额外了解函数调用过程中, 进程栈内存的管理方式),所以通常用一个二维矩阵(表格)来保存不同子问题的答案, 避免重复计算

例题:合唱团(2016网易)
有 n 个学生站成一排,每个学生有一个能力值,从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,返回最大的乘积。 每个输入包含 1 个测试用例。每个测试数据的第一行包含一个整数 n (1 <= n <= 50),表示学生的个数,接下来的一行,包含 n 个整数,按顺序表示每个学生的能力值 ai(-50 <= ai <= 50)。接下来的一行包含两个整数,k 和 d (1 <= k <= 10, 1 <= d <= 50)。
思路:
因为有正有负,负负得正,所以要维护两个dp数组,一个存储最大,一个存储最小。
定义fmax[k][i]表示当选中了k个学生,并且以第i个学生为结尾,所产生的最大乘积;fmin[k][i]表示 当选中了k个学生,并且以第i个学生为结尾,所产生的最小乘积;
当前的最大fmax[k+1][i+1]应该是前面产生的最大乘积当前学生的能力值。那么fmax[k+1][i+1]=max(fmax[k][i]stu[i+1],fmin[k][i]stu[i+1]),即当选中了k个学生后,再选择第i+1编号学生,所产生的最大乘积;
同理fmin[k+1][i+1]=min(fmin[k][i]
stu[i+1],fmax[k][i]*stu[i+1])。
最后,遍历一遍fmax[K][i]求得最大值(i从1~N)。

public class Main{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        while(sc.hasNextInt()){
        int n=sc.nextInt();
        int arr[]=new int[n+1];
        for(int i=1;i<=n;i++){
             arr[i]=sc.nextInt();
        }
        
        int k=sc.nextInt();
        int d=sc.nextInt();
        long[][] fmax=new long[k+1][n+1];//记录最大乘积
        long[][] fmin=new long[k+1][n+1];//记录最小乘积
        // fmax[k][i]表示 : 当选中了k个学生,并且以第i个学生为结尾,所产生的最大乘积;
        // fmin[k][i]表示 : 当选中了k个学生,并且以第i个学生为结尾,所产生的最小乘积;
        long result=Integer.MIN_VALUE;
        for(int i=1;i<=n;i++){
           fmax[1][i]=arr[i];
           fmin[1][i]=arr[i];
            for(int m=2;m<=k;m++){//m是选中的学生数,要构造选中序列,最多选中k个学生
                for(int j=i-1;j>0&&i-j<=d;j--){//j是从第i位往前,控制序列的位置范围不超过d
                   fmax[m][i]=Math.max(fmax[m][i],Math.max(fmax[m-1][j]*arr[i],fmin[m-1][j]*arr[i]));
//fmax[m][i]记录下每个i对应的最大乘积,每次要先和上次的最大乘积还有这次往前增加了一位之后的位置fmax[m-1][j](m-1是因为如果m=2,就是0或者1)或者fmin[m-1][j]与当前值arr[i]的乘积的最大值,再做比较求最大
                   fmin[m][i]=Math.min(fmin[m][i],Math.min(fmax[m-1][j]*arr[i],fmin[m-1][j]*arr[i]));
//最小值和最大值道理一样
                }
            }
            result=Math.max(result,fmax[k][i]);//相当于递归找出最大的乘积
        } 
        System.out.println(result);
        }   
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,013评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,205评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,370评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,168评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,153评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,954评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,271评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,916评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,382评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,877评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,989评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,624评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,209评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,199评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,418评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,401评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,700评论 2 345

推荐阅读更多精彩内容