首页 > 试题广场 >

将路径数组变为统计数组

[编程题]将路径数组变为统计数组
  • 热度指数:470 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
给定一个路径数组paths,表示一张图。
paths[i]==j代表城市i连向城市j,如果paths[i]==i表示i城市是首都,一张图里只会有一个首都,不会有分图且图中除了首都指向自己之外不会有环;
例如:paths={9,1,4,9,0,4,8,9,0,1} 由这个数组表示的图如下图所示。
城市1是首都所以距离为0;离首都距离为1的城市只有城市9;离首都距离为2的城市有城市0,3,7;离首都距离为3的城市有城市4,8;离首都距离为4的城市有城市2,5,6; 所以,距离为0的城市有1座;距离为1的城市有1座;距离为2的城市有3座;距离为3的城市有2座;距离为4的城市有3座;那么统计数组为numArr={1,1,3,2,3,0,0,0,0,0},numArr[i]==j代表距离为i的城市有j座; 要求实现一个void类型的函数,输入一个路径数组paths,直接在原数组上调整,使之变为numArr数组。 paths={9,1,4,9,0,4,8,9,0,1},函数处理后,paths={1,1,3,2,3,0,0,0,0,0}。 要求:如果paths长度为N,时间复杂度为O(N),额外空间复杂度为O(1);

要求统计数组, 首先肯定要求出每个城市的距离。

先考虑已知每个城市的距离的数组arr,如何 O(N) 复杂度转化为统计数组:转化过程中,空间复杂度必须为O(1),因此arr必须同时记录距离和统计量。假如arr[0]=4,表示有一个距离为4的城市,我们可以先将arr[0]标记为已访问,然后找到arr[4],如果arr[4]记录的是统计量,那arr[4]统计量+1(不是真的+1),如果arr[4]不是统计量,则先备份其值,然后将arr[4]设置为1(同样,不是真的1),并使用arr[4]原来的值继续进行上述操作,就能将arr转为统计数组。现在问题是,如何O(1)空间区分距离和统计量,实际上很简单,正负号就行了,统计量为负(所以+1实际上可能是-1),距离为正,然后访问标记给一个特殊值就行了。

回到paths数组转换为距离数组的问题上,paths表示的是一个树形结构的城市, 要在 O(N) 复杂度内求出每个城市的距离,可以使用类似并查集的查找操作的思路: 路径压缩。但是不能用递归,不然空间就不是O(1)而是O(N)了(若树退化为链,那在叶子节点执行递归就是O(N))。但是路径压缩不能简单的向上查找后更新,不然要么结果不正确要么复杂度不是O(N),而是应该在到达某个已知距离的节点的路上不断的将paths[i]反向,也就是如果原本paths[i]=j,则变为paths[j]=i,这样到了已知距离的节点后,可以沿着路径返回来更新距离(如果第一次,肯定是到达根节点,需要设置根节点的距离为0)。同样的,为将paths转换为距离数组,也要用到距离数组 转化 为统计数组的方法。 完成后再转换为统计数组即可,每一步的时间复杂度都是O(N),空间复杂度O(1),所以总得复杂度也是这样
编辑于 2015-03-13 12:26:30 回复(0)
更多回答
top_position()是用来做到空间复杂度
begin()是用来做到时间复杂度
编辑于 2018-01-15 20:15:42 回复(0)
// c++.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <string>
#include <functional>

using namespace::std;
class Solution {
public:
	/**
	*	将路径数组变为统计数组
	*	输入:代表一张图的数组paths
	*  len path的长度
	*	将paths数组变为距离数组numArr
	*/
	void pathArrToNumArr(vector<int>& vec, int len) {
		int cap = 0;
		for (int i = 0; i < vec.size(); ++i) {
			if (vec[i] == i) {
				cap = i;
				break;
			}
		}

		// 采用层序遍历,设置两个队列
		// 当 first_q 队列为空时,表示一层遍历完毕
		// second_q 用来装下一层的节点
		//               1
		//               |
		//               9
		//             / | \
		//            0  3  7   first_q (装载第 i 层节点)
		//           / \
		//          4   8       second_q(装载第 i + 1 层节点)
		//         / \   \
		//        2   5   6
		deque<int> first_q;
		deque<int> second_q;
		first_q.push_back(cap);
		deque<int> result;
		int count = 0;
		while (first_q.empty() == false) {
			int tmp = first_q.front();
			first_q.pop_front(); // 从第 i 层中出一个节点
			for (int i = 0; i < vec.size(); ++i) {
				if (vec[i] == tmp && vec[i] != i) {
					++count; // 统计该节点的孩子数
					second_q.push_back(i); // 把孩子节点加入到 second_q 队列
				}
			}
			// 如果 first_q 不为空,说明我们还没有遍历完一层
			if (first_q.empty() == false){ 
				continue; // 继续 while 循环,直至 first_q 队列为空,这时我们以完成第 i 层的遍历
			}
			else{
				first_q = second_q; // 把第 i + 1 层节点赋给 first_q 队列
				second_q.clear(); // 
				result.push_back(count); // 把第 i 层的孩子数加入结果集
				count = 0;
			}
		}
		result.push_front(1); // 首都到首都的距离(1)放入结果集的开始
		while (result.size()>vec.size())result.pop_back();
		while (result.size()<vec.size())result.push_back(0);
		int length = vec.size();
		vec.clear();
		for (int i = 0; i < length; ++i){
			vec.push_back(result[i]);
		}
	}
};

int main() {
	vector<int> vec = { 0 };
	Solution obj;
	obj.pathArrToNumArr(vec, vec.size());

	return 0;
}

编辑于 2016-08-24 21:03:25 回复(0)
classSolution {
public:
    /**
     *  将路径数组变为统计数组
     *  输入:代表一张图的数组paths
     *  len path的长度
     *  将paths数组变为距离数组numArr
     */
    voidpathArrToNumArr(vector<int>& paths,intlen) {
        inti;
    //int N;
    //cin>>N;
/*  for(i=0;i<len;i++)
    {
        int x;
        cin>>x;
        paths.push_back(x);
    }*/
    intcaptain;
    for(i=0;i<len;i++)if(paths[i]==i)break;
    captain=i;
    for(i=0;i<len;i++)
    {
        //i=0;
        intnext=i,last;
        boolflag=true;
        intpos=i;
        intstep=0;
        while(flag)
        {
            if(paths[pos]==pos||paths[pos]<0)
            {
                if(paths[pos]<0)step=abs(paths[pos]);
                flag=false;
            }
            if(paths[pos]>=0)
                next=paths[pos];
            if(pos!=i)
            {
                swap(last,paths[pos]);
                last=pos;
            }
            else
                last=i;
            pos=next;
        }
        flag=true;
        while(flag)
        {
            next=paths[pos];
            paths[pos]=-(step++);
            if(pos==i)break;
            pos=next;
        }
        paths[captain]=captain;
    }
    paths[captain]=0;
    for(i=0;i<len;i++)
    {
        intpos=i;
        intnext=paths[pos];
        if(next<0)
            paths[pos]=0;
        while(next<0)
        {
            pos=-next;
            next=paths[pos];
            if(paths[pos]<0)paths[pos]=1;
            else
                paths[pos]++;
            if(next==pos)break;
        }
         
    }
    paths[0]=1;
    }
};
发表于 2018-05-08 20:46:03 回复(0)
看了很多通过的答案,空间复杂度并不是O(1)啊,网站在检测答案的时候是不是不会检查时间复杂度和空间复杂度呢?
发表于 2015-05-18 15:29:35 回复(0)
这题应该不能在O(N)时间复杂度和O(1)空间复杂度的条件下完成
显然一个只含距离的数组比这个问题简单。然后问题是统计出这个数组所有数字出现的次数。为此你需要O(N)时间复杂度和O(N)的空间记录统计信息。或者用O(nlogn)时间复杂度,O(1)的空间复杂度。否则你等价在O(N)时间复杂度,O(1)空间复杂度完成了基数排序。
至于取巧比如把int换成2个char来记录,这并不意味着空间复杂度降低了。
发表于 2015-04-03 19:17:00 回复(1)

问题信息

难度:
6条回答 6218浏览

热门推荐

通过挑战的用户