百度2017春招笔试

题目链接

https://www.nowcoder.com/profile/8575360/test/8248155/95827

第四题

给定随机数组a[N](可能包含重复数字),要求对它进行排序。其中排序操作只有一种:将任意一个元素移动到数组末尾。问:最少进行几次操作才能完成任务。

这是一道贪心问题
对于数组中的第i个元素,如果它后面有比它小的元素,这就说明第i个元素理应被移动到末尾去。
另外,应该优先移动较小的元素,这样才能够保证较小元素最后排在最前面。

实际上,这个问题没这么复杂。
用一个备份数组b,把a中元素放到b中,对b数组进行排序。从第一个排好序的元素开始,即最小的元素开始与没排好序数组元素比较,检查有多少个已经是从最小到大好序的,位置可以不连续,但是大的元素必须在小的元素后面,统计出一共有 count个,这些元素是不需要移动的元素,一共有 n 个元素,所以需要移动 n - count 次

#include<stdio.h>
#include<math.h> 
#include<time.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
int N;
int a[1000];
bool has(int x){
    for (int i = x + 1; i < N; i++){
        if (a[i] < a[x])return true;
    }
    return false;
}
int find(){
    int ans = N;
    for (int i = 0; i < N; i++){
        if (has(i)){
            if (a[ans]>a[i])ans = i;
        }
    }
    return ans;
}
void op(int x){
    int t = a[x];
    for (int i = x; i < N - 1; i++)a[i] = a[i + 1];
    a[N - 1] = t;
}
int main(){
    //freopen("in.txt", "r", stdin);
    cin >> N;
    for (int i = 0; i < N; i++){ cin >> a[i]; }
    a[N] = 0xfffffff;
    int ans = 0;
    while (true){
        int pos = find();
        if (pos == N)break;
        op(pos);
        ans++;
    }
    cout << ans << endl;
    return 0;
}

第五题

0~N-1共N个数字有N!种排列方式,对于每一个排列,可以用大于号、小于号将他们连起来,例如:
1<2<4>3<6>5
现在的问题是,只允许用K个小于号把排列连起来,问在这N!种排列中有多少种排列满足小于号的个数不超过K.

这个问题是一道动态规划,f(n,k)表示0~n之间用k个小于号的排列个数,那么,考虑f(n,k)的计算,f(n,k)肯定来源于f(n-1,k)。
对于新来的数字n,考虑将它安排在什么位置:

  • 安排在开头,只需要添加一个大于号
    f(n,k)=f(n-1,k)
  • 安排在结尾,只需要添加一个小于号
    f(n,k)=f(n-1,k-1)
  • 安排在某个小于号上,a<b变为a<n>b,只需要添加一个大于号
    f(n,k)=f(n-1,k)*k
    乘以k表示有k个小于号可以选择来进行替换
  • 安排在某个大于号上,a>b变为a<n>b只需要添加一个小于号
    f(n,k)=f(n-1,k-1)*(n-k-1)
    从0到n-1一共n-2个符号,有k-1个小于号,所以一共有(n-2)-(k-1)=n-k-1个大于号可供选择

这么简单的动态规划我竟然没想到,真是生锈了。

#include<stdio.h> 
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
using namespace std;
int n, k;
int a[1007][1007];
int main(){
	//freopen("in.txt", "r", stdin); 
	cin >> n >> k;
	memset(a, 0, sizeof(a));
	for (int i = 0; i < n; i++)a[i][0] = 1;
	for (int i = 1; i < n; i++){
		for (int j = 1; j <= i; j++){
			a[i][j] = a[i - 1][j - 1]//放在末尾,需要占用一个小于号
				+ a[i - 1][j]//放在开头,只要添加一个大于号
				+ a[i - 1][j] * j//放在小于号上,相当于添加一个大于号
				+ a[i - 1][j-1] * (i - j);//放在大于号上,相当于添加一个小于号
			a[i][j] %= 2017;
		}
	} 
	cout << a[n-1][k] << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/weiyinfu/p/6843642.html