2023-05-14:你的赛车可以从位置 0 开始,并且速度为 +1 ,在一条无限长的数轴上行驶,

赛车也可以向负方向行驶,

赛车可以按照由加速指令 'A' 和倒车指令 'R' 组成的指令序列自动行驶。

当收到指令 'A' 时,赛车这样行驶:

position += speed,

speed *= 2。

当收到指令 'R' 时,赛车这样行驶:

如果速度为正数,那么speed = -1,

否则 speed = 1,

当前所处位置不变。

例如,在执行指令 "AAR" 后,赛车位置变化为 0 --> 1 --> 3 --> 3,

速度变化为 1 --> 2 --> 4 --> -1,

给你一个目标位置 target ,返回能到达目标位置的最短指令序列的长度。

输入:target = 3。

输出:2。

答案2023-05-14:

算法1 - Dijkstra 算法

1.初始化

1.1.设置变量 maxp,表示当前速度下能达到的最大位置,同时计算最大速度 maxs;

1.2.初始化一个优先队列(堆),保存状态 state{speed, cost, position},其中 speed 表示当前速度,cost 表示到达该状态所需的步数,position 表示当前位置;

1.3.根据最初的位置和速度创建初始状态,将其压入优先队列中。

2.Dijkstra 算法遍历状态空间

2.1.从优先队列中取出当前代价最小/速度绝对值最大的状态 state0;

2.2.若该状态满足目标条件,则返回其代价 cost;

2.3.否则,考虑在该状态基础上执行 A 或 R 操作后能够到达的状态:

2.3.1.若执行 A 操作,则新状态为 {speed+1, cost+1, position+(1<<(speed-1))},必须满足新位置不超过 maxp、未访问过;

2.3.2.若执行 R 操作,则新状态为 {speed>0?-1:1, cost+1, position},无需判断是否超过边界、未访问。

2.4.将所有可行的新状态加入优先队列,并继续进行 Dijkstra 遍历。

3.返回 -1,如果无法到达目标位置。

时间复杂度:O(T log T),其中 T 是目标位置 target。每个状态最多被扩展一次,因此总共扩展的状态数不会超过 O(T)。在优先队列中插入和弹出元素的时间复杂度为 O(log T),因此总时间复杂度为 O(T log T)。

空间复杂度:O(T log T)。需要开辟一个大小为 O(T log T) 的优先队列、两个大小为 O(T log T) 的二维数组 visitedPositive 和 visitedNegative,以及一个大小为 O(T) 的判断是否访问过的数组。

算法2 - 动态规划

1.初始化

1.1.创建长度为 target+1 的数组 dp,用于保存到达每个位置的最短步数;

1.2.调用 process(target, dp) 函数进行递归求解。

2.递归求解

2.1.若 dp[target] > 0,说明已经计算过到达该位置的最短步数,直接返回 dp[target];

2.2.计算当前速度下能够到达的最远位置 maxp 和最大速度 maxs;

2.3.如果目标位置就在当前速度达不到的位置之前,则必须先倒车,再加速到目标位置;

若目标位置恰好与当前速度所达到的最远位置相同,则无需倒车。

2.4.对于以上情况,分别计算:

2.4.1.倒车后可以到达的位置 beyond = speed-1-target;

2.4.2.从新的位置开始加速到目标位置,需要的最短步数为 process(beyond, dp),

在此基础上需要增加 1 次倒车操作和 1 次加速操作,因此总步数为 steps+1+process(beyond, dp)。

2.5.如果目标位置在当前速度达到的范围内,则直接加速即可。计算需要的最短步数,以及在此基础上还需要多少次加速操作(steps),

然后遍历所有加速操作的次数 back,计算倒车后可以到达的位置 lack 和需要的步数 steps+1+back+1+process(lack, dp),

取其中的最小值即为当前情况下的最短步数。

2.6.将结果保存到数组 dp 中,并返回。

3.返回 dp[target]。

时间复杂度:O(T log T)。虽然是递归求解,但是可以使用记忆化优化,避免重复计算。每个位置最多只会被计算一次,因此总时间复杂度为 O(T)。

空间复杂度:O(T)。需要创建一个大小为 O(T) 的数组 dp 保存中间结果。

go完整代码如下:

package main

import (
"container/heap"
"fmt"
) type state struct {
speed, cost, position int
} type priorityQueue []state func (pq priorityQueue) Len() int { return len(pq) }
func (pq priorityQueue) Less(i, j int) bool {
return pq[i].cost > pq[j].cost
}
func (pq priorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] } func (pq *priorityQueue) Push(x interface{}) {
item := x.(state)
*pq = append(*pq, item)
} func (pq *priorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
} func abs(x int) int {
if x < 0 {
return -x
}
return x
} func racecar1(target int) int {
maxp := 0
maxs := 1
for maxp <= target {
maxp += 1 << (maxs - 1)
maxs += 1
} heap0 := &priorityQueue{}
visitedPositive := make([][]bool, maxs+1)
visitedNegative := make([][]bool, maxs+1)
for i := range visitedPositive {
visitedPositive[i] = make([]bool, maxp+1)
visitedNegative[i] = make([]bool, maxp+1)
} heap.Push(heap0, state{
speed: 1,
cost: 0,
position: 0,
}) for heap0.Len() > 0 {
current := heap.Pop(heap0).(state)
speed := current.speed
cost := current.cost
position := current.position
if position == target {
return cost
}
if speed > 0 {
if visitedPositive[speed][position] {
continue
}
visitedPositive[speed][position] = true
add(
speed+1,
cost+1,
position+(1<<(speed-1)),
maxp,
heap0,
visitedPositive,
)
add(
-1,
cost+1,
position,
maxp,
heap0,
visitedNegative,
)
} else {
speed := -speed
if visitedNegative[speed][position] {
continue
}
visitedNegative[speed][position] = true
add(
-(speed + 1),
cost+1,
position-(1<<(speed-1)),
maxp,
heap0,
visitedNegative,
)
add(
1,
cost+1,
position,
maxp,
heap0,
visitedPositive,
)
}
}
return -1
} func add(
speed int,
cost int,
position int,
limit int,
heap0 *priorityQueue,
visited [][]bool,
) {
if position >= 0 && position <= limit && !visited[abs(speed)][position] {
heap.Push(heap0, state{
cost: cost,
speed: speed,
position: position,
})
}
} // 动态规划 + 数学
func racecar2(target int) int {
dp := make([]int, target+1)
return process(target, dp)
} func process(target int, dp []int) int {
if dp[target] > 0 {
return dp[target]
}
steps := 0
speed := 1
for speed <= target {
speed <<= 1
steps++
}
ans := 0
beyond := speed - 1 - target
if beyond == 0 {
ans = steps
} else {
ans = steps + 1 + process(beyond, dp)
steps--
speed >>= 1
lack := target - (speed - 1)
offset := 1
for back := 0; back < steps; back++ {
ans = min(ans, steps+1+back+1+process(lack, dp))
lack += offset
offset <<= 1
}
}
dp[target] = ans
return ans
} func min(a, b int) int {
if a < b {
return a
}
return b
} func main() {
target := 3
result1 := racecar1(target)
result2 := racecar2(target)
fmt.Println(result1)
fmt.Println(result2) target = 6
result1 = racecar1(target)
result2 = racecar2(target)
fmt.Println(result1)
fmt.Println(result2)
}

rust完整代码如下:

use std::cmp::Reverse;
use std::collections::BinaryHeap; fn racecar1(target: i32) -> i32 {
let mut maxp = 0;
let mut maxs = 1;
while maxp <= target {
maxp += 1 << (maxs - 1);
maxs += 1;
}
// 0 : 几倍速
// 1 : 花费了几步
// 2 : 当前位置
let mut heap = BinaryHeap::new();
let mut positive = vec![vec![false; (maxp + 1) as usize]; (maxs + 1) as usize];
let mut negative = vec![vec![false; (maxp + 1) as usize]; (maxs + 1) as usize];
heap.push((Reverse(0), Reverse(1), Reverse(0)));
while let Some((Reverse(cost), Reverse(speed), Reverse(position))) = heap.pop() {
if position == target {
return cost;
}
if speed > 0 {
if positive[speed as usize][position as usize] {
continue;
}
positive[speed as usize][position as usize] = true;
add(
speed + 1,
cost + 1,
position + (1 << (speed - 1)),
maxp,
&mut heap,
&positive,
);
add(-1, cost + 1, position, maxp, &mut heap, &negative);
} else {
let speed = -speed;
if negative[speed as usize][position as usize] {
continue;
}
negative[speed as usize][position as usize] = true;
add(
-(speed + 1),
cost + 1,
position - (1 << (speed - 1)),
maxp,
&mut heap,
&negative,
);
add(1, cost + 1, position, maxp, &mut heap, &positive);
}
}
-1
} fn add(
speed: i32,
cost: i32,
position: i32,
limit: i32,
heap: &mut BinaryHeap<(Reverse<i32>, Reverse<i32>, Reverse<i32>)>,
visited: &Vec<Vec<bool>>,
) {
if position >= 0 && position <= limit && !visited[speed.abs() as usize][position as usize] {
heap.push((Reverse(cost), Reverse(speed), Reverse(position)));
}
} fn racecar2(target: i32) -> i32 {
let mut dp = vec![0; (target + 1) as usize];
process(target, &mut dp)
} fn process(target: i32, dp: &mut Vec<i32>) -> i32 {
if dp[target as usize] > 0 {
return dp[target as usize];
}
let mut steps = 0;
let mut speed = 1;
while speed <= target {
speed <<= 1;
steps += 1;
}
let mut ans = 0;
let beyond = speed - 1 - target;
if beyond == 0 {
ans = steps;
} else {
ans = steps + 1 + process(beyond, dp);
steps -= 1;
speed >>= 1;
let mut lack = target - (speed - 1);
let mut offset = 1;
for back in 0..steps {
ans = ans.min(steps + 1 + back + 1 + process(lack, dp));
lack += offset;
offset <<= 1;
}
}
dp[target as usize] = ans;
ans
} fn main() {
let target = 3;
let result1 = racecar1(target);
println!("{}", result1); let result2 = racecar2(target);
println!("{}", result2); let target = 6;
let result1 = racecar1(target);
println!("{}", result1); let result2 = racecar2(target);
println!("{}", result2);
}

c语言第二种方法代码如下:

#include <stdio.h>
#include <stdlib.h> int racecar2_helper(int target, int* dp) {
if (dp[target] > 0) {
return dp[target];
}
int steps = 0;
int speed = 1;
while (speed <= target) {
speed <<= 1;
steps++;
}
int ans = 0;
int beyond = speed - 1 - target;
if (beyond == 0) {
ans = steps;
}
else {
ans = steps + 1 + racecar2_helper(beyond, dp);
steps--;
speed >>= 1;
int lack = target - (speed - 1);
int offset = 1;
for (int back = 0; back < steps; back++) {
ans = (ans < steps + 1 + back + 1 + racecar2_helper(lack, dp)) ?
ans : steps + 1 + back + 1 + racecar2_helper(lack, dp);
lack += offset;
offset <<= 1;
}
}
dp[target] = ans;
return ans;
} int racecar2(int target) {
int* dp = (int*)calloc((target + 1), sizeof(int));
int result = racecar2_helper(target, dp);
free(dp);
return result;
} int main() {
int target = 3;
printf("racecar2: %d", racecar2(target));
target = 6;
printf("racecar2: %d", racecar2(target));
return 0;
}

c++第二种方法代码如下:

#include <iostream>
#include <vector> using namespace std; int racecar2_helper(int target, vector<int>& dp) {
if (dp[target] > 0) {
return dp[target];
}
int steps = 0;
int speed = 1;
while (speed <= target) {
speed <<= 1;
steps++;
}
int ans = 0;
int beyond = speed - 1 - target;
if (beyond == 0) {
ans = steps;
}
else {
ans = steps + 1 + racecar2_helper(beyond, dp);
steps--;
speed >>= 1;
int lack = target - (speed - 1);
int offset = 1;
for (int back = 0; back < steps; back++) {
ans = min(ans, steps + 1 + back + 1 + racecar2_helper(lack, dp));
lack += offset;
offset <<= 1;
}
}
dp[target] = ans;
return ans;
} int racecar2(int target) {
vector<int> dp(target + 1, 0);
return racecar2_helper(target, dp);
} int main() {
int target = 3;
cout << "racecar2: " << racecar2(target) << endl;
target = 6;
cout << "racecar2: " << racecar2(target) << endl;
return 0;
}

2023-05-14:你的赛车可以从位置 0 开始,并且速度为 +1 ,在一条无限长的数轴上行驶, 赛车也可以向负方向行驶, 赛车可以按照由加速指令 ‘A‘ 和倒车指令 ‘R‘ 组成的指令序列自动行驶的更多相关文章

  1. 自己动手写CPU之第五阶段(3)——MIPS指令集中的逻辑、移位与空指令

    将陆续上传本人写的新书<自己动手写CPU>(尚未出版),今天是第17篇.我尽量每周四篇 5.4 逻辑.移位操作与空指令说明 MIPS32指令集架构中定义的逻辑操作指令有8条:and.and ...

  2. ARM指令集中经常使用的存储和载入指令

    ARM微处理器支持载入/存储指令用于在寄存器和存储器之间传送数据,载入指令用于将存储器中的数据传送到寄存器,存储指令则完毕相反的操作.经常使用的载入存储指令例如以下: -  LDR     字数据载入 ...

  3. java selenium启动火狐浏览器报错:Cannot find firefox binary in PATH. Make sure firefox is installed. OS appears to be: VISTA Build info: version: '3.8.1', revision: '6e95a6684b', time: '2017-12-01T19:05:14.666Z

    Cannot find firefox binary in PATH. Make sure firefox is installed. OS appears to be: VISTA Build in ...

  4. 斗篷指令、属性指令、表单指令、条件指令、循环指令、js的Array操作、前台数据库、

    ```python"""1)指令 属性指令:v-bind 表达指令:v-model 条件指令:v-show v-if 循环指令:v-for 斗篷指令:v-cloak 2) ...

  5. 2021.05.14 tarjan

    2021.05.14 tarjan 标准版tarjan 这里使用数组来模拟栈 void tarjan(int x){ ++ind; dfn[x]=low[x]=ind; stacki[++top]=x ...

  6. Python:安装opencv出现错误Could not find a version that satisfies the requirement numpy==1.13.3 (from versions: 1.14.5, 1.14.6, 1.15.0rc2, 1.15.0, 1.15.1, 1.15.2, 1.15.3, 1.15.4, 1.16.0rc1, 1.16.0rc2,

    安装opencv的时候,出现numpy的版本不匹配,卸载了不匹配的版本,重新安装却是一点用都没有,后面尝试了一下这里的提示pip更新,居然安装成功了,看来pip的版本过低真是误事啊. 报错是: Cou ...

  7. ngx_lua_API 指令详解(四)ngx.exec指令

    https://github.com/openresty/lua-nginx-module#ngxexec 参照:http://blog.csdn.net/weiyuefei/article/deta ...

  8. INPUT和CONSTRUCT指令——范例报表查询,作用让用户输入数据,自动生成SQL的WHERE条件,带开窗查询

    INPUT指令 说明:1. 当程序执行到INPUT指令时,会将控制权交给用户,让用户输入数据.2. 用户输入完字段的数据,会将数据回传给程序中的变量接收.3. 只要执行到INPUT的指令,程序会将每个 ...

  9. 寻找大学目标及行动步骤——记ITAEM团队第二期宣讲会(2014.05.14)

    ·昨晚8:00-9:40.在 钟海楼03029 ,进行了ITAEM团队第二期宣讲会(第一期见第一期宣讲会总结).来參加的主要是大一学生.以信院为主.也有法学院.文学院的同学. 在宣讲会中,大家都比較积 ...

  10. OpenSpiel 随笔 05.14

    ------------恢复内容开始------------ 这两天年总算把自己的游戏写完了,也通过了所有的测试. 我将自己的代码上传到了我的github上, 地址是 https://github.c ...

随机推荐

  1. android 尺寸适配相关

    Android上常见度量单位 px(像素):屏幕上的点,绝对长度,与硬件相关. in(英寸):长度单位. mm(毫米):长度单位. pt(磅):1/72英寸,point. dp(与密度无关的像素):一 ...

  2. 文心一言 VS 讯飞星火 VS chatgpt (111)-- 算法导论10.2 2题

    二.用go语言,用一个单链表 L实现一个栈.要求操作 PUSH和 POP 的运行时间仍为 O(1). 文心一言: 在 Go 语言中,我们可以用结构体来实现一个单链表,然后再用栈的相关操作. 以下是一个 ...

  3. vcpkg manifest 的使用

    最近项目上要使用 CMakeLists 管理,由于 Windows 版本有依赖到 vcpkg 提供的库,所以需要使用 vcpkg manifest 来统一设置库的版本,方便后续维护 推荐一个文章,介绍 ...

  4. 使用Docker buildx 为 .NET 构建多平台镜像

    .NET 团队有一篇博客 改进多平台容器支持, 详细介绍了.NET 7 以上的平台可以轻松的使用Docker buildx 工具构建多平台的镜像. buildx 是 Docker 官方提供的一个构建工 ...

  5. 文心一言 VS 讯飞星火 VS chatgpt (114)-- 算法导论10.2 7题

    七.用go语言,给出一个 O(n)时间的非递归过程,实现对一个含 n个元素的单链表的逆转.要求除存储链表本身所需的空间外,该过程只能使用固定大小的存储空间. 文心一言: 在Go语言中,你可以使用迭代方 ...

  6. Java服务总在半夜挂,背后的真相竟然是...

    写在前面 最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了 问题排查 问题复现 为了复现该问题,写 ...

  7. IOI2020 国家集训队作业 Part 1

    日期不对,但要保证顺序正确方便查找少了啥题. 计算几何和实在不会的题没写. 9.20 CF504E Misha and LCP on Tree *3000 二分,hash,树剖 CF505E Mr. ...

  8. go语言写http踩得坑

    1.在运行http时,报错:panic: listen tcp: address xxxx: missing port in address, 初始 代码如下 func HelloWordHander ...

  9. [C++]STL - 队列(Queue) 栈(Stack) 链表(list)

    STL - 队列(Queue) 栈(Stack) 链表(list) Queue 队列 结构特征 这是一种线性储存结构 其数据有先进先出的特点 这种特点被称为FIFO(First In First Ou ...

  10. Weight Balanced Leafy Tree 学习笔记

    前言: 在这里十分十分感谢 \(\text{lxl}\) 和王思齐发明和总结了 \(\text{WBLT}\). 因为网上关于 \(\text{WBLT}\) 的正确讲解(已除去那篇国家集训队论文,不 ...