京东2018秋招编程题
2017-09-10 13:51
375 查看
1.神奇数
将一个数n的各数位分成两部分,两部分之和相等,则称这个数为神奇数。比如242分成[2,2]、[4]。输入一个范围[l,r],输出这个范围内神奇数的个数。
第一种解法,使用回溯法
采用回溯法进行递归搜索
#include <iostream> #include <vector> #include <algorithm> #include<windows.h> using namespace std; long min_num=0,max_num=0; long l; bool opt(int a,int b){ return a<b; } bool recall(vector<int> vec,int l,int pos,int sum){ for(int i=pos;i<vec.size();i++){ l+=vec[i]; if(l==sum){ return true; } if( recall(vec,l,i+1,sum) ){ return true; } if(l>sum){ l-=vec[i]; return false; } l-=vec[i]; } return false; } bool get_digits_recall(long i){ vector<int> vec; long m=i; int sum=0; int digit; while(m>0){ if(m<10) { vec.push_back(m); sum+=m; break; } digit = m%10; sum+=digit; if(digit>0) vec.push_back(digit); m/=10; } if(sum&1) return false; l=0; sort(vec.begin(),vec.end(),opt); return recall(vec,l,0,sum>>1); } int strange_number(){ if(max_num<11) return 0; int cnt=0; for(long i=min_num;i<max_num;i++){ if(get_digits_recall(i)){ cnt++; } } return cnt; } int main(int argc, char const *argv[]) { cin>>min_num>>max_num; DWORD start_time=GetTickCount(); cout<<strange_number(); DWORD end_time=GetTickCount(); cout<<"\nThe run time is:"<<(end_time-start_time)<<"ms!"<<endl;//输出运行时间 return 0; }
第二种解法,使用动态规划
判断一个数是否是神奇数,首先应该获取其各个数位{a1, a2, a3, a4,
…},按照神奇数的定义,需要将数位分成两部分,且两部分元素和相等,因此所有数位的和sum{a1, a2, a3, a4,
…}必为偶数。如果不是偶数,则必然不是神奇数。 因此,这个问题就演变成,在{a1, a2, a3, a4,
…}中寻找一个子集,使得sum{子集} = sum/2。 显然,这是一个0-1背包问题。可以用回溯法、动态规划。
这里使用动态规划,用dp[i][j]表示子数组{a1, a2, a3, a4,…, ai}的元素和是否等于j。 初始dp[i][0] =
true (所有元素都不选,和为j) 如果不选择第i个元素,则dp[i][j] = dp[i-1][j]
如果选择第i个元素,则dp[i][j] = dp[i-1][j-num[i]] 因此,dp[i][j] = dp[i-1][j] ||
dp[i-1][j-num[i]]。 dp
[newSum]即表示是否可以找到一个子集,其元素和为sum/2。
#include <iostream> #include <vector> #include<windows.h> using namespace std; int l=0,r=0; //动态规划 bool canPartition(vector<int>&dicts,int n,int sum) //n代表vector的非零位数 { vector<vector<bool>> dp(n+1,vector<bool>(sum+1,false)); for(int i=0; i<=n; i++) dp[i][0] = true; for(int j=1; j<=sum; j++){ for(int i=1; i<=n; i++){ dp[i][j] = dp[i-1][j]; //不选第i个元素 if(j>=dicts[i-1]) //选第i个元素 dp[i][j] = dp[i-1][j] || dp[i-1][j-dicts[i-1]]; } } for(int i=0;i<n;i++) cout<<dicts[i]<<" "; cout<<endl; for(int j=0; j<=sum; j++){ for(int i=0; i<=n; i++){ cout<<"dp["<<i<<"]["<<j<<"]="<<dp[i][j]<<" "; } cout<<endl; } return dp [sum]; } bool isSqs(int num) { vector<int> dicts(10,0); int k=0,sum=0; while(num!=0){ dicts[k++] = num%10; num /= 10; sum += dicts[k-1]; } if(sum & 1) return false; return canPartition(dicts,k,sum>>1); //sum>>1表示除以2 } int sqs() { if(r<11) return 0; int cnt = 0; for(int i=l; i<=r; i++){ //依次对每一个数进行测试 if(isSqs(i)) cnt++; } return cnt; } int main() { cin>>l>>r; DWORD start_time=GetTickCount(); cout<<sqs(); DWORD end_time=GetTickCount(); cout<<"The run time is:"<<(end_time-start_time)<<"ms!"<<endl;//输出运行时间 return 0; }
2.疯狂的序列
有一个无限数列,{1,2,2,3,3,3,4,4,4,4,…},数字n在数列中出现n次,且是连续的。输入一个整数x,输出序列的第x项的数字。x的范围为[1,10^18]。可以看出是数字n的最后一个n的位置是序列中的第n*(n+1)/2项.
使用for循环,但是会超时
根据 (n+1)*n/2 = x , 得到n^2+n-2x=0 , 解得n=sqrt(1+8x)-1
#include <iostream> #include <math.h> using namespace std; int main(){ long i; cin>>i; double x = (sqrt((double)(1+8*i))-1)/2; cout<<ceil(x)<<endl;//向上取整 return 0; }
相关文章推荐
- 【京东2018秋招前端工程师】编程题-表格操作
- 编程题(1):笔试题-京东软件测试2018实习招聘
- 京东2018秋招编程题
- 京东2018秋招前端笔试编程题
- 编程题(2):京东-笔试题-2018实习招聘
- 编程题(3):京东-笔试题-2018实习招聘
- 京东2018校招在线笔试编程题①
- 京东2018秋招编程题
- 京东2017笔试编程题
- 滴滴出行2018内推编程题
- 2018搜狐内推笔试编程题2
- 网易游戏2018校招编程题
- 2018京东笔试 疯狂序列 神奇数
- 2016京东在线笔试(编程题之一)
- [网易]2018校园招聘编程题真题集合
- 2018趋势科技编程题
- 2018阿里暑期实习线上编程题——数星星
- 网易2018校招编程题3
- 网易2018校园招聘编程题真题集合 (部分)
- 小球的距离(每次弹起的高度为原来的一半)----京东2016研发工程师编程题(二)