名企笔试:Google面试题-目标和
来源:互联网 发布:r语言数据挖掘 薛薇 编辑:程序博客网 时间:2024/06/08 19:15
Problem:
* 给你一个非负的数组数列a1,a2,…,an和一个期望值S。你可以为每一个整数赋值一个新的符号,
* 符号只能从+和-中选择。计算有多少种组合可以另赋过符号的所有数的和等于S。
* 输入样例:nums=[1,1,1,1,1],S=3
* 输出:5
分析:
所有分析见代码注释:
一组数据的算法时间对比:
/**
* 时间对比结果
* 30
* nums = {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1}
* S = 2
* dfs使用时间:5648
* answer = 145422675
* dfsplus使用时间:2643
* answer = 145422675
* dp使用时间:0
* answer = 145422675
*
*/
Code:
package google;import java.util.Date;import java.util.Scanner;/** * @author xiaoran * Time: 2017-09-18 19:04 * Problem: * 给你一个非负的数组数列a1,a2,...,an和一个期望值S。你可以为每一个整数赋值一个新的符号, * 符号只能从+和-中选择。计算有多少种组合可以另赋过符号的所有数的和等于S。 * 输入样例:nums=[1,1,1,1,1],S=3 * 输出:5 */public class Google001 { static int answer = 0; /** * 先使用暴力搜索,再进行剪枝。 * 对于第i个值,有2种选择, * 第1种是选择赋值为+使用;第2种是选择赋值为-使用, * * 参数: * nums:输入的原始的数组 * i:第i的值 * curSum:当值的和的值 * S:期望的目标的和 */ public static void dfs(int[] nums,int i,int curSum,int S){ int len = nums.length;// System.out.println(len); if(i == len){//注意长度是第一满足的条件 if(curSum == S){ answer++; } return ; } //第1种 dfs(nums,i+1,curSum+nums[i],S); //第2种 dfs(nums,i+1,curSum-nums[i],S); } public static int[] getSum(int[] nums){ int len = nums.length; int[] sum = new int[len]; sum[len-1] = nums[len-1]; for(int i=len-2;i>=0;i--){ sum[i] = sum[i+1] + nums[i]; } return sum; } /** * * @param nums:输入的原始数组 * @param i:第i的位置 * @param curSum:当前的值 * @param S:期望的额值 * @param sum[]:后缀和的数组 * 在基础的dfs的基础上添加剪枝,降低时间 * 要明白什么是剪枝,搜索树在还没有到达叶节点的时候,就知道这条路是不通的, * 于是提前结束,降低时间的消耗。我们就是要判断当前的值curSum是否会在后面达到S。 * sum[i]:从i-nums.length的和。 * 对于第i的位置时,如果curSum+sum[i] < S。则表示后面的全是正的也不能达到S。 * if curSum - sum[i] < S。全是负的也不行就要剪枝。 * 两种情况合并得到的S-curSum > Math.abs(sum[i])则进行剪枝 * */ public static void dfsplus(int[] nums,int i,int curSum,int S,int[] sum){ int len = nums.length;// System.out.println(len); if(i == len){//注意长度是第一满足的条件 if(curSum == S){ answer++; } return ; } //判断是否需要剪枝 if(Math.abs(S - curSum) <= sum[i]){ //第1种 dfsplus(nums,i+1,curSum+nums[i],S,sum); //第2种 dfsplus(nums,i+1,curSum-nums[i],S,sum); } } /** * @param args * dfs是一种暴力的方法,剪枝只是一种手段,并不能使其从根本上降低时间。 * dp:动态规划问题就很厉害。 * dp[i,j]:表示前i个值组成j的种类的个数。 * 最后的结果就是dp[nums.length-1,S]. * 中间计算使用两层循环i和j。i:[0,nums.length],j:[0,S] * 好像我们已经解决问题了,但是在运行的过程中j可能出现负数的情况。 * 如果我们对所有的j都加上sum,就可以解决这个问题,对应的结果就是 * sum:数组的和。 * 最后的结果就是dp[nums.length-1,S+sum] * dp转化方程: * dp[i,j+sum] 来源于两种情况dp[i-1,j+sum+nums[i]]和dp[i-1,j+sum-nums[i] * */ public static int findSways(int[] nums,int S){ int ans = 0,sum = 0; for(int a: nums){ sum+=a; } if(sum < Math.abs(S)) return 0;// System.out.println(sum<<1); int dp[][] = new int[nums.length][sum<<1 + 1]; //dp起点需要注意的是nums[0]==0的情况,+nums[0],-nums[0] if(0==nums[0]) dp[0][nums[0]+sum] = 2; else{ dp[0][sum-nums[0]]=1; dp[0][sum+nums[0]]=1; } for(int i=1;i<nums.length;i++){ for(int j=0;j<=sum<<1;j++){ if(j-nums[i]>=0) dp[i][j] += dp[i-1][j-nums[i]]; if(j+nums[i]<=sum<<1) dp[i][j] += dp[i-1][j+nums[i]]; } } return dp[nums.length-1][S+sum]; } public static void main(String[] args) { int n; Scanner sc = new Scanner(System.in); while(sc.hasNext()){ n = sc.nextInt(); int nums[] = new int[n]; for(int i=0;i<n;i++){ nums[i] = sc.nextInt(); } int S = sc.nextInt(); answer = 0; //测试运行时间 long start = new Date().getTime(); dfs(nums,0,0,S); long end = new Date().getTime(); System.out.println("dfs使用时间:"+ (end - start)); System.out.println(answer); answer = 0; start = new Date().getTime(); int[] sum = getSum(nums); dfsplus(nums,0,0,S,sum); end = new Date().getTime(); System.out.println("dfsplus使用时间:"+ (end - start)); System.out.println(answer); start = new Date().getTime(); int ans = findSways(nums,S); end = new Date().getTime(); System.out.println("dp使用时间:"+ (end - start)); System.out.println(ans); } }}/** * 时间对比结果 * 30 * nums = {1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1} * S = 2 * dfs使用时间:5648 * answer = 145422675 * dfsplus使用时间:2643 * answer = 145422675 * dp使用时间:0 * answer = 145422675 * */
阅读全文
0 0
- 名企笔试:Google面试题-目标和
- Google面试题 | 目标和
- 100多家软件公司和IT名企招聘软件工程师面试题和笔试题
- Google校园招聘和Google面试题
- 名企的面试题
- 名企经典面试题
- google开源软件职位笔试面试题
- 一些微软 google IBM 笔试题 面试题
- C++并发实战:面试题3:一道google笔试题
- moto & google笔试题目-STL/C++面试题
- C和C++笔试面试题汇总
- C和C++笔试面试题汇总
- 嵌入式笔试面试题:C和C++汇总试题
- 微软笔试面试题
- 腾讯笔试面试题
- 笔试面试题
- 笔试面试题整理
- Flex笔试 (面试题)
- Delphi中ClientDataSet浅析
- Error: java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException
- redis安装和主从配置
- 扩展欧几里得算法(exgcd)
- java 数据库操作JDBC
- 名企笔试:Google面试题-目标和
- 斐波那契数列变形之跳台阶问题
- jbpm6.3安装
- 截止JDK1.8版本,java并发框架支持的锁
- 01--Mysql入门
- 探索laravel里的encrypt和decrypt实现
- 如何用VS2017C++写hello world程序---从下载到新建项目
- 圆的一些操作
- delphi把Clientdataset的Delta保存到数据库