为了更好的阅读体检,可以查看我的算法学习网
本题在线评测链接: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 count≤10000
- 3 ≤ s t e p s . l e n g t h ≤ 10000 3 \leq steps.length \leq 10000 3≤steps.length≤10000
- − 100000 ≤ s t e p s [ i ] ≤ 100000 -100000 \leq steps[i] \leq 100000 −100000≤steps[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)
#include
#include
#include
#include
#include
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;
}
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]]}]")
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]));
}
}
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]]}]`);
});
});
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)