【备战秋招】每日一题:2023.05-B卷-华为OD机试 - 五子棋迷

为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接:P1354

题目描述

张兵和王武是五子棋迷,工作之余经堂切磋棋艺。这不,这会儿又下起来了。走了一会儿,轮张兵了,对着一条线思考起来了,这条线上的棋子分布如下:

用数组表示: − 1 -1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 − 1 -1 1

棋了分布说明:

- − 1 -1 1代表白子, 0 0 0代表空位, 1 1 1代表黑子

  • 数组长度 L L L,满足 1 < L < 40 1<L< 40 1<L<40 L L L为奇数

你得帮他写一个程序,算出最有利的出子位置。 最有利定义:

  • 找到一个空位 ( 0 ) (0) (0),用棋子 ( 1 / − 1 ) (1/-1) (1/1)填充该位置,可以使得当前子的最大连续长度变大
  • 如果存在多个位置,返回最靠近中间的较小的那个坐标
  • 如果不存在可行位置,直接返回 − 1 -1 1
  • 连续长度不能超过 5 5 5个(五字棋约束)

输入描述

第一行: 当前出子颜色。
第二行: 当前的棋局状态。

输出描述

1 1 1个整数,表示出子位置的数组下标

样例

输入

1
-1 0 1 1 1 0 1 -1 1

输出

5

说明

当前为黑子 ( 1 ) (1) (1),放置在下标为 5 5 5的位置,黑子的最大连续长度,可以由 3 3 3 5 5 5

输入

-1
-1 0 1 1 1 0 1 0 1 -1 1

输出

1

说明

当前为白子,唯一可以放置的位置下标为 1 1 1,白字的最大长度,由 1 1 1变为 2 2 2

输入

1
0 0 0 0 1 0 0 0 0 1 0

输出

5

说明

可以的位置很多, 5 5 5最接近中间的位置坐标

思路:模拟

按照题意模拟即可。

有几个要求,

  • 首先要使得落子后,当前子的最大连续长度变长
  • 但是最大连续长度不能超过 5
  • 如果存在多个落子位置都满足上述两个要求,则选择最靠近中间位置的一个,如果有多个位置都最靠近中间,则选择左边的
  • 如果不存在这样的位置,返回-1

时间复杂度: O ( L 2 ) O(L^2) O(L2)

类似题目推荐

  1. 携程 P1303. 2023.05.25-暑期-第一题-游游的整数切割

代码

C++

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

int main()
{
    int x = 1;
    cin >> x;

    vector<int> vec;
    int num;
    // 因为长度未知,所以直到读不到数为止,这是一个数组,有若干个数
    while (cin >> num) vec.push_back(num);

    // 找到当前子在未落子前的最大连续长度 cur_max
    int cur_max = 0;
    for (int i = 0, j = 0; i < vec.size(); ++i) {
        if (vec[i] == x) j += 1;
        else j = 0;
        cur_max = max(cur_max, j);
    }

    // len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
    vector<int> len(vec.size());
    // max_len 表示落子后,包含当前落子位置的最大连续长度
    int max_len = 0;
    for (int i = 0; i < vec.size(); ++i) {
        if (vec[i] == 0) {
            int L = i - 1, R = i + 1;
            // 向左
            while (L >= 0 && vec[L] == x) L -= 1;
            // 向右
            while (R < vec.size() && vec[R] == x) R += 1;
            // 只有 <= 5 才合法
            if (R - L - 1 <= 5) {
                len[i] = R - L - 1;
                max_len = max(max_len, R - L - 1);
            }
        }
    }

    // 如果 max_len 小于 cur_max,说明不存在答案
    if (max_len <= cur_max || vec.empty()) {
        cout << "-1\n";
        return 0;
    }

    // 否则找距离中间位置最近的一个点,其落子后的连续长度最长
    int ansidx = -1;
    int mid = (vec.size() - 1) / 2;
    for (int i = 0; i < vec.size(); ++i) {
        if (len[i] > cur_max) {
            if (ansidx == -1 || abs(ansidx - mid) > abs(i - mid)) {
                ansidx = i;
            }
        }
    }

    cout << ansidx << "\n";

    return 0;
}

python

x = int(input())
vec = list(map(int, input().split()))

# 找到当前子在未落子前的最大连续长度 cur_max
cur_max = 0
j = 0
for i in range(len(vec)):
    if vec[i] == x:
        j += 1
    else:
        j = 0
    cur_max = max(cur_max, j)

# len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
len_vec = [0] * len(vec)
max_len = 0
for i in range(len(vec)):
    if vec[i] == 0:
        L, R = i - 1, i + 1
        # 向左
        while L >= 0 and vec[L] == x:
            L -= 1
        # 向右
        while R < len(vec) and vec[R] == x:
            R += 1
        # 只有 <= 5 才合法
        if R - L - 1 <= 5:
            len_vec[i] = R - L - 1
            max_len = max(max_len, R - L - 1)

# 如果 max_len 小于 cur_max,说明不存在答案
if max_len <= cur_max or len(vec) == 0:
    print("-1")
else:
    # 否则找距离中间位置最近的一个点,其落子后的连续长度最长
    ansidx = -1
    mid = (len(vec) - 1) // 2
    for i in range(len(vec)):
        if len_vec[i] > cur_max:
            if ansidx == -1 or abs(ansidx - mid) > abs(i - mid):
                ansidx = i
    print(ansidx)

Java

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        int x = in.nextInt();

        List<Integer> vec = new ArrayList<>();
        while (in.hasNextInt()) {
            int num = in.nextInt();
            vec.add(num);
        }

        // 找到当前子在未落子前的最大连续长度 cur_max
        int cur_max = 0;
        int j = 0;
        for (int i = 0; i < vec.size(); ++i) {
            if (vec.get(i) == x) {
                j += 1;
            } else {
                j = 0;
            }
            cur_max = Math.max(cur_max, j);
        }

        // len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
        int[] len_arr = new int[vec.size()];
        int max_len = 0;
        for (int i = 0; i < vec.size(); ++i) {
            if (vec.get(i) == 0) {
                int L = i - 1, R = i + 1;
                // 向左
                while (L >= 0 && vec.get(L) == x) L -= 1;
                // 向右
                while (R < vec.size() && vec.get(R) == x) R += 1;
                // 只有 <= 5 才合法
                if (R - L - 1 <= 5) {
                    len_arr[i] = R - L - 1;
                    max_len = Math.max(max_len, R - L - 1);
                }
            }
        }

        // 如果 max_len 小于 cur_max,说明不存在答案
        if (max_len <= cur_max || vec.size() == 0) {
            System.out.println("-1");
        } else {
            // 否则找距离中间位置最近的一个点,其落子后的连续长度最长
            int ansidx = -1;
            int mid = (vec.size() - 1) / 2;
            for (int i = 0; i < vec.size(); ++i) {
                if (len_arr[i] > cur_max) {
                    if (ansidx == -1 || Math.abs(ansidx - mid) > Math.abs(i - mid)) {
                        ansidx = i;
                    }
                }
            }
            System.out.println(ansidx);
        }
    }
}

Go

package main

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

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanWords)

    scanner.Scan()
    x, _ := strconv.Atoi(scanner.Text())

    vec := make([]int, 0)
    for scanner.Scan() {
        num, _ := strconv.Atoi(scanner.Text())
        vec = append(vec, num)
    }

    // 找到当前子在未落子前的最大连续长度 cur_max
    cur_max := 0
    j := 0
    for i := 0; i < len(vec); i++ {
        if vec[i] == x {
            j += 1
        } else {
            j = 0
        }
        cur_max = max(cur_max, j)
    }

    // len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
    lenArr := make([]int, len(vec))
    maxLen := 0
    for i := 0; i < len(vec); i++ {
        if vec[i] == 0 {
            L, R := i-1, i+1
            // 向左
            for L >= 0 && vec[L] == x {
                L -= 1
            }
            // 向右
            for R < len(vec) && vec[R] == x {
                R += 1
            }
            // 只有 <= 5 才合法
            if R-L-1 <= 5 {
                lenArr[i] = R - L - 1
                maxLen = max(maxLen, R-L-1)
            }
        }
    }

    // 如果 maxLen 小于 cur_max,说明不存在答案
    if maxLen <= cur_max || len(vec) == 0 {
        fmt.Println("-1")
    } else {
        // 否则找距离中间位置最近的一个点,其落子后的连续长度最长
        ansIdx := -1
        mid := (len(vec) - 1) / 2
        for i := 0; i < len(vec); i++ {
            if lenArr[i] > cur_max {
                if ansIdx == -1 || abs(ansIdx-mid) > abs(i-mid) {
                    ansIdx = i
                }
            }
        }
        fmt.Println(ansIdx)
    }
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

func abs(a int) int {
    if a < 0 {
        return -a
    }
    return a
}

Js

process.stdin.resume();
process.stdin.setEncoding('utf-8');
let input = '';
process.stdin.on('data', (data) => {
    input += data;
    return;
});
process.stdin.on('end', () => {
    const lines = input.trim().split('\n');
    const x = parseInt(lines[0]);
    const vec = lines[1].split(' ').map(Number);

    // 找到当前子在未落子前的最大连续长度 cur_max
    let cur_max = 0;
    let j = 0;
    for (let i = 0; i < vec.length; i++) {
        if (vec[i] === x) {
            j += 1;
        } else {
            j = 0;
        }
        cur_max = Math.max(cur_max, j);
    }

    // len[i] 表示落子到 i 这个位置,包含 i 这个位置的当前子的最大长度
    let lenArr = new Array(vec.length).fill(0);
    let maxLen = 0;
    for (let i = 0; i < vec.length; i++) {
        if (vec[i] === 0) {
            let L = i - 1, R = i + 1;
            // 向左
            while (L >= 0 && vec[L] === x) {
                L -= 1;
            }
            // 向右
            while (R < vec.length && vec[R] === x) {
                R += 1;
            }
            // 只有 <= 5 才合法
            if (R - L - 1 <= 5) {
                lenArr[i] = R - L - 1;
                maxLen = Math.max(maxLen, R - L - 1);
            }
        }
    }

    // 如果 maxLen 小于 cur_max,说明不存在答案
    if (maxLen <= cur_max || vec.length == 0) {
        console.log("-1");
    } else {
        // 否则找距离中间位置最近的一个点,其落子后的连续长度最长
        let ansIdx = -1;
        let mid = Math.floor((vec.length - 1) / 2);
        for (let i = 0; i < vec.length; i++) {
            if (lenArr[i] > cur_max) {
                if (ansIdx === -1 || Math.abs(ansIdx - mid) > Math.abs(i - mid)) {
                    ansIdx = i;
                }
            }
        }
        console.log(ansIdx);
    }
});
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

塔子哥学算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值