拼多多笔试真题-评价展示序列(C++/Py/Java /Js/Go)

评价展示序列

拼多多技术岗 8月2号笔试 第二题

题目内容

多多是电商平台的前端开发工程师,负责商品详情页的评价展示模块。评价区收到 NNN 条评价,每条评价有一个星级评分(111 到 555 星)。多多希望将评价按一定顺序展示,使得任意两条评价相邻的星级不同 ,避免连续高分或低分影响用户判断。在所有合法的展示顺序中,请输出 字典序最小 的一种,或报告不可能。

给定 NNN 条评价的星级 r1,r2,...,rNr_1,r_2,\dots,r_Nr1,r2,...,rN (1≤ri≤5)(1 \le r_i \le 5)(1≤ri≤5)。将它们重新排列为一行,使得相邻两个元素的值不同。 如果存在合法排列,输出字典序最小 的一种;如果不存在,输出 −1-1−1。

两个排列 aaa 和 bbb 的字典序比较:从左到右找到第一个 ai≠bia_i \ne b_iai=bi 的位置,若 ai<bia_i < b_iai<bi 则 aaa 的字典序更小。

输入描述

第一行一个整数 NNN (1≤N≤105)(1 \le N \le 10^5)(1≤N≤105)。

第二行 NNN 个整数 r1,r2,...,rNr_1,r_2,\dots,r_Nr1,r2,...,rN (1≤ri≤5)(1 \le r_i \le 5)(1≤ri≤5),表示每条评价的星级。

输出描述

如果不存在合法排列,输出 −1-1−1。

否则输出 NNN 个整数,用空格分隔,表示字典序最小的一种合法排列顺序。

样例1

输入

复制代码
5
1 1 1 2 3

输出

复制代码
1 2 1 3 1

说明

样例1:111 出现 333 次,⌈5/2⌉=3\lceil 5/2 \rceil = 3⌈5/2⌉=3,恰好不超限。字典序最小的排列为 (1,2,1,3,1)(1,2,1,3,1)(1,2,1,3,1)。

样例2

输入

复制代码
4
1 1 1 1

输出

复制代码
-1

说明

样例2:111 出现 444 次,⌈4/2⌉=2\lceil 4/2 \rceil = 2⌈4/2⌉=2,超过上限,不可能。

样例3

输入

复制代码
6
5 5 3 5 3 1

输出

复制代码
1 5 3 5 3 5

说明

样例3:555 出现 333 次,⌈6/2⌉=3\lceil 6/2 \rceil = 3⌈6/2⌉=3,恰好不超限。字典序最小的排列为 (1,5,3,5,3,5)(1,5,3,5,3,5)(1,5,3,5,3,5)(首位取最小可用值 111,此后在保证剩余元素仍可合法排列的前提下逐位取最小)。

题解

思路

解题算法:贪心 + 数学

  1. 统计每个数字出现次数使用cnt数组存储。
  2. 数字能否组成相同数不相邻的序列取决于出现次数最多的maxCnt。当前可放置位置数量为m时,出现次数最多为maxCnt, 那么要将对应数组合合法序列,需要满足maxCnt + (maxCnt - 1) <= m, 对应需要满足maxCnt <= (m + 1) / 2maxCnt - 1为最小间隔数量
  3. 通过2的规律可以判断出初始题目给出的数据是否能构成合法排序。不合法直接返回-1即可。
  4. 同时要想构造字典序最小的排序方式,可以通过贪心从前往后枚举1, 5确定每个位置元素,判断剩余数字是否能够组成合法序列。
  5. 判断能否合法序列逻辑在2的基础上要引入额外一个限制,last,如果maxCnt对应元素的上一个确定位置last值时,需要满足maxCnt + (maxCnt - 1) <= m - 1(第一个位置不能放), 对应需要满足maxCnt <= m / 2
  6. 算法总体时间复杂度为O(n)

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;


bool check(vector<int>& cnt, int last, int remainng) {
    if (remainng == 0) {
        return true;
    }
    
    for (int i = 1; i <= 5; i++) {
        int limit = (i == last) ? remainng / 2 : (remainng + 1) /2;
        if (cnt[i] > limit) {
            return false;
        }
    }
    return true; 
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int N;
    cin >> N;
    vector<int> cnt(6, 0);
    for (int i = 0; i < N; i++) {
        int x;
        cin >> x;
        cnt[x]++;
    }
    
    
    vector<int> ans;
    int last = -1;
    
    bool ok =  check(cnt, last, N);
    if (!ok) {
        cout << "-1\n";
        return 0;
    }
    
    while (ans.size() < N) {
        bool found = false;
        
        // 按从小到大进行尝试
        for (int x = 1; x <= 5; x++) {
            if (cnt[x] == 0 || x == last) {
                continue;
            }
            cnt[x]--;
            if (check(cnt, x, N - 1 - ans.size())) {
                ans.push_back(x);
                last = x;
                found = true;
                break;
            }
            // 恢复
            cnt[x]++;
        }
        
        // 没有合法选择
        if (!found) {
            cout << "-1\n";
            return 0;
        }
    }
    
    // 输出合法方案
    for (int i = 0; i < N; i++) {
        if (i) {
            cout << " ";
        }
        cout << ans[i];
    }
    return 0;
    
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {

    static boolean check(int[] cnt, int last, int remaining) {
        if (remaining == 0) {
            return true;
        }

        for (int i = 1; i <= 5; i++) {
            int limit = (i == last) ? remaining / 2 : (remaining + 1) / 2;
            if (cnt[i] > limit) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine().trim());

        int[] cnt = new int[6];

        String[] nums = br.readLine().trim().split(" ");
        for (int i = 0; i < N; i++) {
            int x = Integer.parseInt(nums[i]);
            cnt[x]++;
        }

        ArrayList<Integer> ans = new ArrayList<>();

        int last = -1;

        boolean ok = check(cnt, last, N);
        if (!ok) {
            System.out.println("-1");
            return;
        }

        while (ans.size() < N) {
            boolean found = false;

            // 按从小到大进行尝试
            for (int x = 1; x <= 5; x++) {

                if (cnt[x] == 0 || x == last) {
                    continue;
                }

                cnt[x]--;

                if (check(cnt, x, N - 1 - ans.size())) {
                    ans.add(x);
                    last = x;
                    found = true;
                    break;
                }

                // 恢复
                cnt[x]++;
            }

            // 没有合法选择
            if (!found) {
                System.out.println("-1");
                return;
            }
        }

        // 输出合法方案
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < N; i++) {
            if (i > 0) {
                sb.append(" ");
            }
            sb.append(ans.get(i));
        }

        System.out.println(sb);
    }
}

python

python 复制代码
import sys


def check(cnt, last, remaining):
    if remaining == 0:
        return True

    for i in range(1, 6):
        limit = remaining // 2 if i == last else (remaining + 1) // 2
        if cnt[i] > limit:
            return False

    return True


N = int(input())

cnt = [0] * 6

nums = list(map(int, input().split()))

for x in nums:
    cnt[x] += 1


ans = []
last = -1

ok = check(cnt, last, N)

if not ok:
    print("-1")
    sys.exit()


while len(ans) < N:

    found = False

    # 按从小到大进行尝试
    for x in range(1, 6):

        if cnt[x] == 0 or x == last:
            continue

        cnt[x] -= 1

        if check(cnt, x, N - 1 - len(ans)):
            ans.append(x)
            last = x
            found = True
            break

        # 恢复
        cnt[x] += 1


    # 没有合法选择
    if not found:
        print("-1")
        sys.exit()


# 输出合法方案
print(" ".join(map(str, ans)))

javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

let input = [];

rl.on("line", function(line) {
    input.push(line.trim());
});

rl.on("close", function() {

    function check(cnt, last, remaining) {
        if (remaining === 0) {
            return true;
        }

        for (let i = 1; i <= 5; i++) {
            let limit = (i === last) 
                ? Math.floor(remaining / 2) 
                : Math.floor((remaining + 1) / 2);

            if (cnt[i] > limit) {
                return false;
            }
        }

        return true;
    }


    let N = Number(input[0]);

    let cnt = new Array(6).fill(0);

    let nums = input[1].split(" ").map(Number);

    for (let x of nums) {
        cnt[x]++;
    }


    let ans = [];

    let last = -1;


    let ok = check(cnt, last, N);

    if (!ok) {
        console.log("-1");
        return;
    }


    while (ans.length < N) {

        let found = false;

        // 按从小到大进行尝试
        for (let x = 1; x <= 5; x++) {

            if (cnt[x] === 0 || x === last) {
                continue;
            }

            cnt[x]--;

            if (check(cnt, x, N - 1 - ans.length)) {
                ans.push(x);
                last = x;
                found = true;
                break;
            }

            // 恢复
            cnt[x]++;
        }


        // 没有合法选择
        if (!found) {
            console.log("-1");
            return;
        }
    }


    // 输出合法方案
    console.log(ans.join(" "));
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)


func check(cnt []int, last int, remaining int) bool {

	if remaining == 0 {
		return true
	}

	for i := 1; i <= 5; i++ {

		limit := 0

		if i == last {
			limit = remaining / 2
		} else {
			limit = (remaining + 1) / 2
		}

		if cnt[i] > limit {
			return false
		}
	}

	return true
}


func main() {

	in := bufio.NewReader(os.Stdin)

	var N int
	fmt.Fscan(in, &N)

	cnt := make([]int, 6)

	for i := 0; i < N; i++ {
		var x int
		fmt.Fscan(in, &x)
		cnt[x]++
	}


	ans := make([]int, 0)

	last := -1


	ok := check(cnt, last, N)

	if !ok {
		fmt.Println("-1")
		return
	}


	for len(ans) < N {

		found := false


		// 按从小到大进行尝试
		for x := 1; x <= 5; x++ {

			if cnt[x] == 0 || x == last {
				continue
			}

			cnt[x]--


			if check(cnt, x, N-1-len(ans)) {

				ans = append(ans, x)
				last = x
				found = true
				break
			}


			// 恢复
			cnt[x]++
		}


		// 没有合法选择
		if !found {
			fmt.Println("-1")
			return
		}
	}


	// 输出合法方案
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()


	for i := 0; i < N; i++ {

		if i > 0 {
			fmt.Fprint(out, " ")
		}

		fmt.Fprint(out, ans[i])
	}
}
相关推荐
无限码力5 小时前
拼多多笔试真题-多多送快递(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多机试·拼多多笔试·拼多多技术岗真题
无限码力1 天前
拼多多笔试真题-多多的告警网络(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多笔试·拼多多技术岗笔试真题
无限码力4 天前
拼多多笔试真题-多多的GPU批处理调度(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多机试·拼多多笔试·拼多多技术岗笔试真题
无限码力7 天前
拼多多笔试真题-多多的灰度发布(C++/Py/Java /Js/Go)
拼多多·拼多多机试·拼多多技术岗笔试·拼多多笔试·拼多多技术岗笔试真题
市象23 天前
新拼姆会是大号版“SHEIN”吗?
拼多多
无限码力1 个月前
拼多多笔试真题【多多的特殊三元组】
拼多多·拼多多笔试真题·拼多多笔试题库·拼多多技术岗笔试·pdd笔试笔试真题
无限码力1 个月前
拼多多笔试真题-多多的Boss挑战(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多技术岗笔试题目·拼多多机试·pdd笔试真题
无限码力1 个月前
拼多多笔试真题-多多捕蝇(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多技术岗笔试题目·拼多多机试·pdd笔试真题
无限码力1 个月前
拼多多笔试真题-多多的营救行动(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多笔试题库·拼多多技术岗笔试