8-11 網易筆試算法
記一次網易筆試算法題解題思路,由于原題目描述太形象化了,這裡題目描述就開門見山了。所知題目就5個(應該還有但是我找不到啊o(╯□╰)o)其中加法乘法和遊戲很容易這裡就不給出了。
瞌睡題
題目描述
給定一個數組數組的每一個位置代表一個分值,同時給定同樣長度的數組每個位置都是0或1代表分值數組對應位置是否能擷取(1可以,0不行),給定整形k代表可以叫醒k分鐘,即從任意位置開始連續k個位置的分值都可以加上,而不管對應位置是否為1或0,在隻能叫醒一次時求可以獲得的分值的最大值
輸入
- n,k代表數組長度,和叫醒一次能醒的時間
- n個數代表各個時間的分值
- n個數,都是0或1代表該時間是否清醒,1清醒,0不清醒
輸出
可以獲得的最大分值
解題思路
利用滑動視窗的方式計算最大值,視窗大小為k,一開始在視窗中為數組前k個數,視窗開始向後移動,此時如果左邊出視窗的分值對應清醒位置為0則要剪去這個分數。
代碼
//主函數負責輸入輸出
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()) {
int len = in.nextInt();
int wake = in.nextInt();
int[] score = new int[len], wakeTime = new int[len];
for(int i = ;i < len;i++){
score[i] = in.nextInt();
}
for(int i = ;i < len;i++){
wakeTime[i] = in.nextInt();
}
System.out.println(solve(wake,score,wakeTime));
}
in.nextInt();
}
private static int solve(int wake, int[] score, int[] wakeTime) {
int max = ;
int i = ;
//初始前k個分值在視窗中
for(;i < wake && i < score.length;i++){
max += score[i];
}
int tmp = max;
//其實這裡循環到score.length - k即可,即最後一個分值進入視窗
for(;i < score.length;i++){
//如果左邊出視窗元素對應位置為0要減去這個分值
if(wakeTime[i - wake] == ){
tmp -= score[i - wake];
}
//目前進入位置本身為1,說明不管在不在視窗都要加上
//這裡max是目前最大值,而tmp是視窗目前情況最大值
if(wakeTime[i] == ){
max += score[i];
}
tmp += score[i];
max = Math.max(tmp ,max);
}
return max;
}
}
收貨題目
題目描述
地上有n堆蘋果,每堆ai個,求第q個蘋果屬于第幾堆
輸入
- 第一行n代表有n堆
- n個數ai代表第i堆有幾個蘋果
- m代表詢問m次
- m個qi代表每次詢問是第qi個蘋果
輸出
m行,每行代表qi詢問的答案
解題思路
首先計算出到目前堆為止一共有幾個蘋果,如輸入為[1,3,5,7],則到目前堆的蘋果數為1,4,9,16,那麼第qi個蘋果如果小于等于a0則屬于第一堆,大于a0小于等于a1在第二堆,依次類推。很明顯可以用二分查找來搜尋答案。如果用java可以用Arrays.binarySearch()方法,函數在找到時會傳回找到元素的位置,不存在時會傳回一個負數,它的絕對值代表第一個大于它的數在第幾個位置,例如對于上面例子數組a,binarySearch(a,3)傳回-2,代表第一個大于它的是在第二個位置,即下标1。
代碼
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNext()){
int n = in.nextInt();
int[] arr = new int[n];
for(int i = ;i < n;i++){
arr[i] = in.nextInt();
//計算目前位置一共有幾個蘋果
if(i>){
arr[i] += arr[i-];
}
}
int m = in.nextInt();
for (int i = ;i < m;i++){
System.out.println(solve(arr, in.nextInt()));
}
}
in.close();
}
private static int solve(int[] arr, int pos) {
int ans = Arrays.binarySearch(arr,pos);
return ans >= ? ans + : Math.abs(ans);
}
//為了了解自己寫一個binarySearch的類似實作,這裡不存在直接傳回第一個大于他的元素的位置
private static int binarSeach(int[] arr,int val){
int left = , right = arr.length - ;
while (left < right){
int mid = left + (right - left >> );
if(arr[mid] == val)
return mid;
if(arr[mid] < val)
left = mid + ;
else
right = mid;
}
return left;
}
字典
題目描述
輸入整形n,m代表這個字典裡有n個’a’,m個’z’,他們所有的排列組合按字典順序排序,求第k個字元串。
輸入
n,m,k分别代表n個’a’,m個’z’,求字典第k個字元串
輸出
第k個字元串,如n = 2,m = 2,k = 6輸出”zzaa”
因為n = 2, m = 2,在字典有
aazz, azaz, azza, zaaz, zaza, zzaa
解題思路
這題的第一反應就是做一個帶有重複元素的字元數組的全排列,然後按字典排序,或者直接将每次全排列的結果加入優先權隊列或者TreeSet都可以。然而全排列時間複雜度為O(n!)輸入m和n為0-100明顯會逾時,其實在n+m>22左右就開始逾時了。是以這題應該是用dp算法來解決。
我們設dp[n][m]代表n個’a’,m個’z’有dp[n][m]個排列組合的數量,很明顯dp[n][m]所有情況可以由兩種方式得到,dp[n][m-1]代表n個’a’,m-1個’z’,由它的所有情況前面加一個’z’得到,還有dp[n-1][m]的所有情況前面加’a’得到(其實這個’a’或’z’加最前最後中間都行,但是一定要所有情況加在同一位置,并且加在最前面好了解這個算法)。這樣我們可以得到公式如下
dp[n][m] = dp[n][m-1] + dp[n-1][m]
那麼如何通過dp[n][m]得到第k個的字元串呢?首先明顯的是k > dp[n][m]肯定不存在傳回-1。那麼當k <= dp[n][m]時,按字典順序肯定先走a在前的是以先看dp[n-1]m如果k小于它說明肯定是前面加a,反之如果比dp[n-1][m]大,說明它在dp[n][m-1]中,前面要加z,并且它是dp[n][m-1]中的第k-dp[n-1][m]個(a開頭的消耗了dp[n-1][m]個),那麼直到尋找到dp的邊界,剩下的’a’和’z’按照先’a’的原則追加到末尾
代碼
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNext()){
int n = in.nextInt();
int m = in.nextInt();
int k = in.nextInt();
System.out.println(solve(n, m, k));
}
in.close();
}
private static String solve(int n, int m, int k){
int[][] dp = new int[n+][m+];
initDp(dp);
if(k > dp[n][m])
return "-1";
int i = n, j = m;
StringBuilder sb = new StringBuilder();
while(i > && j > ){
int addA = dp[i-][j], addZ = dp[i][j-];
if(addA >= k){//屬于前dp[i-1][j]個追加'a'
sb.append('a');
i--;//因為是從dp[i-1][j]來的是以下一次對dp[i-1][j]繼續搜尋
n--;//消耗了一個'a','a'剩餘數量減1
}else {
sb.append('z');
j--;
m--;
k = k - addA;
}
}
while (n > ) {
sb.append('a');
n--;
}
while (m > ) {
sb.append('z');
m--;
}
return sb.toString();
}
//初始化dp
private static void initDp(int[][] dp){
int n = dp.length, m = dp[].length;
for(int i = ;i < m;i++){
dp[][i] = ;
}
for(int j = ;j < n;j++){
dp[j][] = ;
}
for(int i = ;i < n;i++){
for(int j = ;j < m;j++){
dp[i][j] = dp[i-][j] + dp[i][j-];
}
}
}