题意:

给你一个无限长的数轴,刚开始你在位置处,你每次可以向左或者向右移动个单位,现在有次询问,第次询问给你一个数字,问从起点位置到所在位置最少需要多少步?

解法一(最短路,不可AC)

显然我们可以根据题意构建一张以数轴上的数字为点,边权为的无向图,边表示数字变化成数字的一次操作
那么对于第个询问,答案为起点到点的最短路
代码:
class Solution {
public:
    vector<int> MinimumTimes(vector<int>& arr) {
        int mx_q=0;//询问最大的数字
        for(auto& x:arr){
            mx_q=max(mx_q,x);//求解询问最大的数字
        }
        mx_q+=20;//由于可以向左走,且一次最多走11个单位,故将范围扩大20
        vector<int> dis(mx_q+1,0x3f3f3f3f);//动态分配内存,且初始化一个极大值
        vector<int>* gr=new vector<int>[mx_q+1];//邻接表存图,动态内存分配
        for(int i=0;i<=mx_q;i++){//对于每个点向周围连边
            if(i+3<=mx_q){
                //向右走3
                gr[i].push_back(i+3);
                gr[i+3].push_back(i);
            }
            if(i+7<=mx_q){
                //向右走7
                gr[i].push_back(i+7);
                gr[i+7].push_back(i);
            }
            if(i+11<=mx_q){
                //向右走11
                gr[i].push_back(i+11);
                gr[i+11].push_back(i);
            }
            if(i-3>=0){
                //向左走3
                gr[i].push_back(i-3);
                gr[i-3].push_back(i);
            }
            if(i-7>=0){
                //向左走7
                gr[i].push_back(i-7);
                gr[i-7].push_back(i);
            }
            if(i-11>=0){
                //向左走11
                gr[i].push_back(i-11);
                gr[i-11].push_back(i);
            }
        }
        queue<int> que;//bfs队列
        que.push(0);//起点
        dis[0]=0;
        while(!que.empty()){
            int x=que.front();
            que.pop();
            for(auto v:gr[x]){
               if(dis[v]>dis[x]+1){
                   //松弛操作
                   dis[v]=dis[x]+1;
                   que.push(v);
               }
            }
        }
        vector<int> ans;
        for(auto x:arr){
            //记录答案
            ans.push_back(dis[x]);
        }
        return ans;
    }
};
时间复杂度:,总共有级别个点,BFS求解每个点只会访问一次,故总的时间复杂度为
空间复杂度:,邻接表存图,距离数组,队列的空间大小都是级别的,答案数组的空间大小为级别的,故总的空间复杂度为

解法二(取模优化)

我们知道当足够大时,肯定是先走很多步11,直到走到距离足够近时,再走小的步数进行微调
于是我们可以对一个较小的距离范围求解最短路
然后对于一个询问,我们可以枚举最后一段的长度,前面的长度全部用步数11的方法走,最后取最小的步数即可

代码:
class Solution {
public:
    /**
     * 把所有询问的答案按询问顺序放入vector里
     * @param arr int整型vector 要查询坐标的数组
     * @return int整型vector
     */
    int dis[31];//30>=2*11,足够小的范围
    vector<int> gr[31];//邻接表存图
    vector<int> MinimumTimes(vector<int>& arr) {
        memset(dis,0x3f,sizeof dis);//初始化一个极大值
        for(int i=0;i<=30;i++){
            gr[i].clear();//多测清空
        }
        for(int i=0;i<=30;i++){
            //枚举每个点
            if(i+3<=30){
                //向右走3
                gr[i].push_back(i+3);
                gr[i+3].push_back(i);
            }
            if(i+7<=30){
                //向右走7
                gr[i].push_back(i+7);
                gr[i+7].push_back(i);
            }
            if(i+11<=30){
                //向右走11
                gr[i].push_back(i+11);
                gr[i+11].push_back(i);
            }
            if(i-3>=0){
                //向左走3
                gr[i].push_back(i-3);
                gr[i-3].push_back(i);
            }
            if(i-7>=0){
                //向左走7
                gr[i].push_back(i-7);
                gr[i-7].push_back(i);
            }
            if(i-11>=0){
                //向左走11
                gr[i].push_back(i-11);
                gr[i-11].push_back(i);
            }
        }
        dis[0]=0;
        queue<int> que;
        que.push(0);
        while(!que.empty()){
            int x=que.front();
            que.pop();
            for(auto v:gr[x]){
                if(dis[v]>dis[x]+1){
                    //松弛操作
                    dis[v]=dis[x]+1;
                    que.push(v);
                }
            }
        }
        vector<int> ans;
        for(auto x:arr){
            int res=0x3f3f3f3f;
            for(int k=0;k<=2;k++){
                //枚举一共走多少个11
                if(x>=k*11){
                   //x/11-k为走的11的个数
                   res=min(res,dis[x-(x/11-k)*11]+(x/11-k));
                }
            }
            ans.push_back(res);
        }
        return ans;
    }
};
时间复杂度:,由于预处理点的数量只有31个,故建图和BFS求解最短路的时间复杂度为,有次询问,每次询问的复杂度都为,故总的时间复杂度为
空间复杂度:,邻接表存图,距离数组,队列所占空间都为级别,答案数组的空间为级别,故总的空间复杂度为