字節跳動提前批第二批筆試題

第二批一共四道編程題,2道dp一道暴力搜索,一道田忌賽馬,雖然有兩道是經典題,但本菜雞還是扛不住,宇宙條這難度還是讓人服氣的,另外面經就不寫了,涼麪寫起來不舒服…

第一題田忌賽馬

赤裸裸的田忌賽馬,有興趣的話可以去網上搜一搜hdu,沒什麼變動。
有兩隊人,輸入n,表示每隊有n個人,接着輸入兩行,每行n個數字,每個數字代表這個隊員的速度。兩隊進行賽跑,贏一局,加一分,輸一局,減一分,平局,不加不減,問你怎麼跑第一隊積分最高。

思路:
對兩隊人按照從快到慢都進行排序,之後從慢馬開始比:
如果a隊跑的慢的比b隊跑得慢的快,那麼直接加一分,繼續比
如果a隊跑的慢的比b隊跑的慢的慢,那麼我們實際操作時讓a隊跑的慢的跟b隊跑的最快的比,此時減一分
如果兩隊的跑的慢的一樣快,那麼此時先比較兩隊跑的快的,a隊跑的快的如果比b隊跑得快的還要快,那麼加一分,反之減一分,其餘情況爲平局,不加不減。

//
//  toutiao1.cpp
//  Algorithm
//
//  Created by huangyi on 2019/7/7.
//  Copyright © 2019 Leetcode. All rights reserved.
//

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 2020;
int a[maxn], b[maxn];
bool cmp(int a, int b) {
    return a > b;
}
int main()
{
    int n, len1, len2;
    int res = 0;
    scanf("%d", &n);
        for(int i = 0; i < n; i++) {
            scanf("%d %d", &a[i], &b[i]);
        }
        //將兩隊馬從快到慢排序
        sort(a, a + n, cmp);
        sort(b, b + n, cmp);
        //最慢的馬的位置
        len1 = len2 = n - 1;
        int i = 0, j = 0;
        while(i <= len1 && j <= len2) {
            //a隊慢馬 > b隊慢馬,加一分
            if(a[len1] > b[len2]) {
                res++;
                len1--;
                len2--;
            } else if(a[len1] < b[len2]) {
                res--;//我們讓j++,len1--就是讓a隊的慢馬跟b隊的快馬比
                j++;
                len1--;
            } else {
                
                if(i < len1) {
                    if(a[i] <= b[j]) {
                        //a隊的快馬不能贏
                        if(a[len1] < b[j]) {
                            res--;
                        }
                        len1--;
                        j++;
                    } else {
                        //a隊的快馬贏了
                        res++;
                        i++;
                        j++;
                    }
                } else {
                    //平局
                    len1--;
                    len2--;
                }
            }
        }
    printf("%d\n", res);
    return 0;
}

第二題,撿石頭遊戲

輸入n,表示一共有n塊石頭,之後輸入n個數,每個數代表當前石頭的積分。現在有兩隊人,a隊和b隊。假設a隊先開始撿石頭,第一次可以撿1到2塊,之後b隊撿石頭,b隊可以撿一隊的兩倍範圍,也就是b隊可以撿2到4塊,一直輪流下去。問你怎麼減石頭,a隊可以得到最高的積分,輸出該積分。

輸入樣例:
5
2 7 9 4 3

輸出樣例:
9
  • 參考LeetCode1140石子游戲二:
#include<bits/stdc++.h>
using namespace std;
int n,a[2010];
int stoneGameII(vector<int>& piles) {
        int len = piles.size();
        vector<vector<int> > dp(len, vector<int>(len, 0));
        vector<int> sum(len, 0);
        sum.back() = piles.back();
        //逆序部分和
        for(int i = len-2; i >= 0; i--) {
            sum[i] = sum[i+1] + piles[i];
        }
        //逆序查找,dp[i][j]表示當前在i位置,m = j - 1 可以獲得的最大數
        for(int i = len-1; i >= 0; i--) {
        //m的範圍爲1到len,都遍歷一遍
            for(int j = 0; j < len; j++) {
                int m = j + 1;
                //剩下的時候可以一次性拿完
                if(2*m >= len-i) {
                    dp[i][j] = sum[i];
                } else {
                //剩下的石頭一次性拿不完,取最大的
                    for(int k = 1; k <= 2*m; k++) {
                        dp[i][j] = max(dp[i][j], sum[i]-dp[i+k][max(k,m)-1]);
                    }
                }
            }
        }
        return dp[0][0];
    }
int main() {
    scanf("%d", &n);
    vector<int> nums;
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        nums.push_back(a[i]);
    }
    int res = stoneGameII(nums);
    printf("%d\n", res);
    return 0;
}
//
//  toutiao2.cpp
//  Algorithm
//
//  Created by huangyi on 2019/7/7.
//  Copyright © 2019 Leetcode. All rights reserved.
//
#include<bits/stdc++.h>
using namespace std;

int n,a[2010],b[2010],c[2010],dp[2010][2010];

int main(){
    scanf( "%d" , &n);
        for( int i=1 ; i<=n ; i++ ){
            scanf( "%d" , &a[i] );
        }
        b[n] = a[n];
        for( int i=n-1 ; i>=1 ; i-- ){
            b[i] = a[i]+b[i+1];
        }
        for( int i=1 ; i<=n ; i++ ){
            dp[n][i] = a[n];
        }
        for( int i=n-1 ; i>=1 ; i-- ){
            for( int k=1 ; i+k<=n ; k++ ){
                c[k] = b[i]-dp[i+k][k];
            }
            for( int k=2 ; i+k<=n ; k++ ){
                c[k] = max( c[k] , c[k-1] );
            }
            for( int j=1 ; j<=n ; j++ ){
                int k = min(j*2,n-i);
                dp[i][j] = c[k];
                if( i+j+j>n )
                    dp[i][j] = b[i];
            }
        }
        printf( "%d\n" , dp[1][1] );
    return 0;
}

第三題,圍桌子

輸入n和m,表示一共有n個人,之後一行輸入n個數,分別表示每個人的身高,現在要求這些人圍成一圈,要求是相鄰的兩個人身高不能超過m,問你一共有幾種方案。

一開始沒什麼想法,用了兩個if竟然也過了好幾個樣例…後來看了下,n個人的範圍很小,不超過10。可以猜想這題應該是個暴力搜索。不過代碼最後沒有提交測試過,不知道對不對…

//
//  toutiao3.cpp
//  Algorithm
//
//  Created by huangyi on 2019/7/7.
//  Copyright © 2019 Leetcode. All rights reserved.
//

#include<bits/stdc++.h>
using namespace std;

int n,m,ans,a[15],b[15],v[15];

void dfs( int idx ){
    if( idx == n ){
        if( abs(b[0] - b[n-1]) <= m ) ans++;
        return;
    }
    for( int i = 0; i < n; i++ ){
        if( v[i] ) continue;
        if( abs(a[i] - b[idx - 1]) <= m ){
            v[i] = 1;
            b[idx] = a[i];
            dfs(idx + 1);
            v[i] = 0;
        }
    }
}

int main(){
        scanf( "%d%d" , &n , &m );
        for( int i=0 ; i<n ; i++ ){
            scanf( "%d" , &a[i] );
        }
        if( n==1 ){
            printf( "1\n" );
        }else if( n==2&&abs( a[0]-a[1] )<=m ){
            printf( "1\n" );
        }else{
            for( int i = 0; i < n; i++ ){
                v[i] = 0;
            }
            ans  = 0;
            for( int i=0 ; i<n ; i++ ){
                b[0] = a[i];
                v[i] = 1;
                dfs( 1 );
            }
            printf( "%d\n" , ans );
        }
    return 0;
}

01揹包

輸入n和m,代表揹包上限和物品個數,輸入w數組和c數組,分別代表每個物品的消耗和積分,問你怎麼取物品放到揹包裏,積分能夠最大。

//
//  toutiao4.cpp
//  Algorithm
//
//  Created by huangyi on 2019/7/7.
//  Copyright © 2019 Leetcode. All rights reserved.
//

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100;
const int maxv = 2010;
//w[]消耗數組,c[]積分數組,dp[][]
//令dp[i][j]表示前i件物品(1<=i<=n,0<=j<=n)恰好裝入容量爲j的揹包中所能獲得的最大價值
int w[maxn],c[maxn],dp[maxn][maxv];
int main()
{
    int n,m;
    //n爲揹包上限,m爲物品個數
    scanf("%d%d",&n, &m);
    for(int i = 0;i < m;i++){
        scanf("%d %d",&w[i], &c[i]);
    }
    for(int i = 1; i <= m; i++){
        for(int j = w[i]; j <= n; j++){
            dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+c[i]);
        }
    }
    
    printf("%d\n",dp[m][n]);
    return 0;
}

阿里巴巴兩道筆試題

三個線程交替打印alialiali…,一個打印a,一個打印l,一個打印i

思路:可以利用Condition的await和signal方法來等待和喚醒線程

package thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


public class FirstThreadTest {

	public static void main(String[] args) {
		final AlternateDemo ad = new AlternateDemo();

		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					ad.loopA();
				}
			}
		}, "a").start();

		new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i < 10; i++) {
					ad.loopB();
				}
			}
		}, "l").start();

		new Thread(new Runnable() {
			@Override
			public void run() {

				for (int i = 0; i < 10; i++) {
					ad.loopC();
					//System.out.println("-----------------------------------");
				}
			}
		}, "i").start();
	}

}

class AlternateDemo {

	private int number = 1; //當前正在執行線程的標記

	private Lock lock = new ReentrantLock();
	private Condition condition1 = lock.newCondition();
	private Condition condition2 = lock.newCondition();
	private Condition condition3 = lock.newCondition();

	public void loopA() {
		lock.lock();
		try {
			//1. 判斷
			if (number != 1) {
				condition1.await();
			}
			//2. 打印
			System.out.print(Thread.currentThread().getName());
			//3. 喚醒
			number = 2;
			condition2.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void loopB() {
		lock.lock();
		try {
			//1. 判斷
			if (number != 2) {
				condition2.await();
			}
			//2. 打印
			System.out.print(Thread.currentThread().getName());
			//3. 喚醒
			number = 3;
			condition3.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

	public void loopC() {
		lock.lock();
		try {
			//1. 判斷
			if (number != 3) {
				condition3.await();
			}
			//2. 打印
			System.out.print(Thread.currentThread().getName());
			//3. 喚醒
			number = 1;
			condition1.signal();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.unlock();
		}
	}

}

字符串模式匹配

有一個字符串它的構成是詞+空格的組合,如“北京 杭州 杭州 北京”, 要求輸入一個匹配模式(簡單的以字符來寫), 比如 aabb, 來判斷該字符串是否符合該模式, 舉個例子:
pattern = “abba”, str=“北京 杭州 杭州 北京” 返回 true
pattern = “aabb”, str=“北京 杭州 杭州 北京” 返回 false
pattern = “baab”, str=“北京 杭州 杭州 北京” 返回 true

思路,建立兩個map,把兩個字符數組和單詞數組分別映射到map裏去,鍵分別爲字符和單詞,值都是int。同時建立兩個int數組,分別用來存放相應map映射的值。
最後只需要比較兩個數組是否相等即可


//
//  Ali2.cpp
//  Algorithm
//
//  Created by huangyi on 2019/7/12.
//  Copyright © 2019 Leetcode. All rights reserved.
//

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull base = 1000003;
const int mod  = 1e9+7;

string pattern,str;
map<char,int> mp1;
map<string,int> mp2;
int num1,num2;
vector<int>a;
vector<int>b;
bool same(){
    if( a.size()!=b.size() ){
        return false;
    }
    for( int i=0 ; i<a.size() ; i++ ){
        if( a[i]!=b[i] ){
            return false;
        }
    }
    return true;
}
int main(){
    cin>>pattern;
    getchar();
    getline( cin , str );
    for( int i=0 ; i<pattern.length() ; i++ ){
        if( !mp1.count(pattern[i]) ){
            mp1[pattern[i]] = ++num1;
        }
        a.push_back(mp1[pattern[i]]);
    }
    string part = "";
    for( int i=0 ; i<=str.length() ; i++ ){
        if( i==str.length()||str[i]==' ' ){
            if( !mp2.count(part) ){
                mp2[part] = ++num2;
            }
            b.push_back(mp2[part]);
            part = "";
        }else{
            part = part+str[i];
        }
    }
    if( same() ) {
        printf( "true\n" );
    } else {
        printf( "false\n" );
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章