【备战秋招】每日一题: 2023.05-B卷-华为OD机试 - 跳房子II

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

题目描述

跳房子,也叫跳飞机,是一种世界性的儿童游戏。

游戏参与者需要分多个回合按顺序跳到第 1 1 1格直到房子的最后一格,然后获得一次选房子的机会,直到所有房子被选完,房子最多的人获胜。

跳房子的过程中,如果有踩线等违规行为,会结束当前回合,甚至可能倒退几步。假设房子的总格数是 c o u n t count count,小红每回合可能连续跳的步数都放在数组 s t e p s steps steps中,请问数组中是否有一种步数的组合,可以让小红三个回合跳到最后一格?

如果有,请输出索引和最小的步数组合(数据保证索引和最小的步数组合是唯一的)。

注意:数组中的步数可以重复,但数组中的元素不能重复使用。

输入描述

第一行输入为房子总格数 c o u n t count count,它是 i n in int整数类型

第二行输入为每回合可能连续跳的步数,它是 i n t int int整数数组类型

输出描述

返回索引和最小的满足要求的步数组合 (顺序保持
s t e p s steps steps中原有顺序)

备注

- c o u n t ≤ 10000 count \leq 10000 count10000
- 3 ≤ s t e p s . l e n g t h ≤ 10000 3 \leq steps.length \leq 10000 3steps.length10000
- − 100000 ≤ s t e p s [ i ] ≤ 100000 -100000 \leq steps[i] \leq 100000 100000steps[i]100000

样例

输入

[1,4,5,2,0,2]
9

输出

[4,5,0]

说明

输入

[1,5,2,0,2,4]
9

输出

[5,2,2]

说明

输入

[-1,2,4,9]
12

输出

[-1,4,9]

说明

思路:排序+双指针

双指针变种题,没学过双指针的童鞋点这里,简化一下题目,考虑一件事,如果给定一个有序的数组,求找和为x的两个数,则可以用两个指针l,r指向头和尾,若和大于x则r--即右指针左移,若和小于x则l++,即左指针右移,当等于x时便是答案

考虑到一件事,本题要求索引和最小,我们创建一个pair(val, idx)数组,其val存放值,idx存放下标,递增排序(先按val升序排,当两个值val相等时,按idx升序排),这样我们在执行双指针时,遇到和等于x时,我们只需右移右指针即可,因为在值相等的情况下,下标是升序排的,所以左移左指针只会让索引和增加。

上面的思路是找两个数的算法,时间复杂度是 O ( n ) O(n) O(n)

回到本题,我们找三个数,在按上述排序方法排完序后,遍历所有数,对于一个数,可以固定这个数a[i]后,在其后找两个数和为x - a[i]的数,这样总体时间复杂度便是 O ( n 2 ) O(n^2) O(n2)

代码

C++
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;

int main() {
    char c;
    int x, idx = 0;
    vector<pair<int,int>> a; // 创建一个pair(val, idx)数组,其val存放值,idx存放下标
    vector<int> arr;
    while (~scanf("%c%d", &c, &x)) {
        a.push_back({x, idx++});
        arr.push_back(x);
    }
    int m = a.back().first, n = a.size() - 1;
    a.pop_back();
    // 升序排列
    sort(a.begin(), a.end());
    int minn = 3 * n;
    vector<int> vi;
    for (int i = 0; i < n - 2; ++i) {
        auto [sum, idx] = a[i];
        int l = i + 1, r = n - 1;
        while (l < r) {
            int tot = a[l].first + a[r].first + sum; 
            int sum_id = a[l].second + a[r].second + idx;
            if (tot == m) { // 判断和是否是需要的值
                if (minn > sum_id) { // 判断索引最小
                    minn = sum_id;
                    vi = {idx, a[l].second, a[r].second};
                }
                r--;
            } else if (tot > m) { // 和大于m,右指针左移使和减少
                r--;
            } else { // 否则,左指针右移使和增大
                l++;
            }
        }
    }
    sort(vi.begin(), vi.end());
    printf("[%d,%d,%d]", arr[vi[0]], arr[vi[1]], arr[vi[2]]);
    return 0;
}
python
arr = list(map(int, input()[1:-1].split(',')))
m = int(input())
n = len(arr)
a = []
for i in range(n):
    a.append([arr[i], i]) # 存放值和下标

a.sort() # 升序排列
minn = 3 * n
vi = []

for i in range(n - 2):
    sum_val = a[i][0]
    idx = a[i][1]
    l = i + 1
    r = n - 1

    while l < r:
        tot = a[l][0] + a[r][0] + sum_val
        sum_id = a[l][1] + a[r][1] + idx

        if tot == m: # 判断和是否是需要的值
            if minn > sum_id: # 判断索引最小
                minn = sum_id
                vi = [idx, a[l][1], a[r][1]]
            r -= 1
        elif tot > m:
            r -= 1 # 和大于m,右指针左移使和减少
        else:
            l += 1 # 否则,左指针右移使和增大

vi.sort()
print(f"[{arr[vi[0]]},{arr[vi[1]]},{arr[vi[2]]}]")

Java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String inputStr = scanner.nextLine();
        List<Integer> arr = new ArrayList<>();
        String[] arrStr = inputStr.substring(1, inputStr.length() - 1).split(",");
        for (String numStr : arrStr) {
            arr.add(Integer.parseInt(numStr.trim()));
        }

        int m = scanner.nextInt();
        int n = arr.size();
        int[][] a = new int[n][2];

        for (int i = 0; i < n; i++) { // 存放值和下标
            a[i][0] = arr.get(i);
            a[i][1] = i;
        }

        Arrays.sort(a, (x, y) -> Integer.compare(x[0], y[0])); // 升序排列

        int minn = 3 * n;
        int[] vi = new int[3];

        for (int i = 0; i < n - 2; i++) {
            int sum_val = a[i][0];
            int idx = a[i][1];
            int l = i + 1;
            int r = n - 1;

            while (l < r) {
                int tot = a[l][0] + a[r][0] + sum_val;
                int sum_id = a[l][1] + a[r][1] + idx;

                if (tot == m) { // 判断和是否是需要的值
                    if (minn > sum_id) { // 判断索引最小
                        minn = sum_id;
                        vi[0] = idx;
                        vi[1] = a[l][1];
                        vi[2] = a[r][1];
                    }
                    r--;
                } else if (tot > m) {
                    r--; // 和大于m,右指针左移使和减少
                } else {
                    l++; // 否则,左指针右移使和增大
                }
            }
        }

        Arrays.sort(vi);
        System.out.printf("[%d,%d,%d]", arr.get(vi[0]), arr.get(vi[1]), arr.get(vi[2]));
    }
}

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

rl.on('line', function (inputStr) {
    const arr = [];
    const arrStr = inputStr.substring(1, inputStr.length - 1).split(",");
    for (let numStr of arrStr) {
        arr.push(parseInt(numStr.trim()));
    }

    rl.on('line', (line) => {
        const m = parseInt(line);
        const n = arr.length;
        const a = new Array(n).fill().map(() => new Array(2));

        for (let i = 0; i < n; i++) { // 存放值和下标
            a[i][0] = arr[i];
            a[i][1] = i;
        }

        a.sort((x, y) => x[0] - y[0]); // 升序排列

        let minn = 3 * n;
        const vi = new Array(3).fill(0);

        for (let i = 0; i < n - 2; i++) {
            const sum_val = a[i][0];
            const idx = a[i][1];
            let l = i + 1;
            let r = n - 1;

            while (l < r) {
                const tot = a[l][0] + a[r][0] + sum_val;
                const sum_id = a[l][1] + a[r][1] + idx;

                if (tot === m) { // 判断和是否是需要的值
                    if (minn > sum_id) { // 判断索引最小
                        minn = sum_id;
                        vi[0] = idx;
                        vi[1] = a[l][1];
                        vi[2] = a[r][1];
                    }
                    r--;
                } else if (tot > m) { // 和大于m,右指针左移使和减少
                    r--;
                } else { // 否则,左指针右移使和增大
                    l++;
                }
            }
        }

        vi.sort((x, y) => x - y);
        console.log(`[${arr[vi[0]]},${arr[vi[1]]},${arr[vi[2]]}]`);
    });
});
Go
package main

import (
	"fmt"
	"sort"
	"strings"
	"strconv"
)

func main() {
	var input string
	fmt.Scan(&input)

	arrStr := strings.Split(input[1:len(input)-1], ",")
	arr := make([]int, len(arrStr))
	for i, numStr := range arrStr {
		arr[i], _ = strconv.Atoi(strings.TrimSpace(numStr))
	}

	var m int
	fmt.Scan(&m)

	n := len(arr)
	a := make([][2]int, n)
	for i := 0; i < n; i++ { // 存放值和下标
		a[i] = [2]int{arr[i], i}
	}

	sort.Slice(a, func(i, j int) bool { // 升序排列
		return a[i][0] < a[j][0]
	})

	minn := 3 * n
	var vi []int

	for i := 0; i < n-2; i++ {
		sumVal := a[i][0]
		idx := a[i][1]
		l := i + 1
		r := n - 1

		for l < r {
			tot := a[l][0] + a[r][0] + sumVal
			sumID := a[l][1] + a[r][1] + idx

			if tot == m { // 判断和是否是需要的值
				if minn > sumID { // 判断索引最小
					minn = sumID
					vi = []int{idx, a[l][1], a[r][1]}
				}
				r--
			} else if tot > m { // 和大于m,右指针左移使和减少
				r--
			} else { // 否则,左指针右移使和增大
				l++
			}
		}
	}

	sort.Ints(vi)
	result := fmt.Sprintf("[%d,%d,%d]", arr[vi[0]], arr[vi[1]], arr[vi[2]])
	fmt.Println(result)
}

时间复杂度

O ( n 2 ) O(n^2) O(n2)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

塔子哥学算法

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

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

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

打赏作者

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

抵扣说明:

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

余额充值