字节跳动提前批第二批笔试题

第二批一共四道编程题,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
#include
#include
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
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
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
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
#include
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
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;
}

你可能感兴趣的:(dp,笔试面试题)