去面试,有道笔试题是PHP随机生成坐标的,自己想了两种种策略(1.随机生成x,和y坐标,然后遍历去重 2.把所有坐标生成出来,然后随机取200),但感觉不是很高效,发出来看看有没有跟好的实现
//点反对的人,把你们的代码留下,否则就别装逼!
function() { var array = {0...9999}; var arrayMaxIndex = 9999; var result; for(int i = 0; i < 200; i++) { var index = rand(0, arrayMaxIndex); var num = array[index]; var x = num / 100; var y = num % 100; result.add(x, y); array.RemoveAt(index); arrayMaxIndex--; } return result; }
我这个效率如何?这是伪代码,没有php环境
这种方法可以,效率应该比我想的那两种好点,具体试试才知道
刚试了下100*100的矩阵,随机取2000个坐标,这种方法耗时0.4秒多,用for循环把100*100的坐标全存在数组,然后随机取2000这种方法耗时0.01秒级别,数量级越大你说的方法效率越低,还有就是num % 100;100倍数这些求余完就是0了,还需要处理下
@北冥那条鱼: 谢谢,看来还得试试才知道,我没有试,惭愧
@北冥那条鱼: 你说的那种耗时0.01s的方法能不能贴出代码让我学习一下啊,谢谢
@北冥那条鱼: 我用c#写了2个方法。第一个方法差不多耗时300毫米,第二个方法更少一些,耗时200毫米。而且每个方法重复调用了50次:
using System; using System.Collections.Generic; using System.Diagnostics; namespace Rand { struct Point { public int X { get; set; } public int Y { get; set; } }
class Program { static void Main(string[] args) { Stopwatch watch = new Stopwatch(); watch.Start(); for (int i = 0; i < 50; i++) { Point[] points = GetPoints(2000); } watch.Stop(); Console.WriteLine("GetPoints:" + watch.ElapsedMilliseconds); watch.Reset(); watch.Start(); for (int i = 0; i < 50; i++) { Point[] pointsAgain = GetPoints2(2000); } watch.Stop(); Console.WriteLine("GetPoints2:" + watch.ElapsedMilliseconds); Console.WriteLine("press any key to exit"); Console.ReadKey(); } private static Point[] GetPoints(int count) { Point[] points = new Point[count]; List<Point> allPoints = new List<Point>(); for (int i = 0; i < 100; i++) { for (int j = 0; j < 100; j++) { allPoints.Add(new Point { X = i, Y = j }); } } int totalPointsCount = 10000; Random random = new Random(); for (int i = 0; i < count; i++) { int index = random.Next(totalPointsCount--); points[i] = allPoints[index]; allPoints.RemoveAt(index); } return points; } private static Point[] GetPoints2(int count) { Point[] points = new Point[count]; List<int> allNumbers = new List<int>(); for (int i = 0; i < 10000; i++) { allNumbers.Add(i); } int totalPointsCount = 10000; Random random = new Random(); for (int i = 0; i < count; i++) { int index = random.Next(totalPointsCount--); int number = allNumbers[index]; int x = number / 100; int y = number % 100; allNumbers.RemoveAt(index); points[i] = new Point { X = x, Y = y }; } return points; } } }
@北冥那条鱼: 100的倍数求余等于0对的呀,表示纵坐标是0。100对应的坐标是(1,0)
@会长: 比如说100*100的矩阵,坐标(10,200)这个点,200%100的话就是(10,0),所以需要判断下如果是0的话yCoord就应该是纵坐标纬度
@会长: 没有没有,大家相互学习相互讨论
@会长: PHP代码$lng 表示经度,$lat 纬度,$num 生成坐标数,一开始觉得这种方法要生成所有坐标,不是最好的,昨晚试了下,数量级越大好像耗时比其他越低,但这种方法肯定不是最好的方法
function uniqueCoord($lng,$lat,$num){
$coord = array();
$count = 0;
for($i = 1; $i <= $lng; $i++){
for($j = 1;$j <= $lat;$j++){
$coord[]=array('coordX'=> $i,'coordY'=> $j);
}
}
$randArr = array_rand($coord,$num);
foreach($randArr as $key => $value){
$arr[$value+1] = $coord[$value];
}
return $arr;
}
@北冥那条鱼: 我觉得我们好像说岔道了。我的意思是这样的:
给一个100*100的方阵中的每个点编号,从左到右,从上到下依次是0,1,2,3,.....9999。比如随机取出一个数字101,那么就代表横坐标为1,纵坐标也为1那个点,根据公式 x * 100 + y = 101 算出x=1,y=1。如果随机得到的数是200,就代表(2,0)那个点,200/1=2,200%100=0。每次随机产生一个数后,就从原始的包含所有点(长度为10000的列表)中把它去掉,保证不会产生重复的点。
@北冥那条鱼: 你这个是用了php内置函数array_rand。那可能比较高效了吧,毕竟是牛人写的函数。
首先100*100就是10000
生成100不重复的0-10000的随机数.
百度:洗牌算法.
这种方法我试试
遇到重复的再随机一次(逃
这种需要不停遍历以前的数组,效率应高不会太高
@北冥那条鱼: 并不会..你弄一个hash.每一次获取随机数后就往hash表里插入.
知道hash表的长度到你要的要求.就行了
@吴瑞祥: OK,我试试
var _startTime = new Date().getTime(); /* 二分查找算法 * * */ var rank = function(key,arr){ var o = 0; var k = arr.length - 1; while(o <= k){ var mid = Math.floor((o+k)/2); if(key > arr[mid]){ o = mid + 1; } else if(key < arr[mid]){ k = mid - 1; }else{ return mid; } } return -1; } //最后结果 var result = []; var j = { //矩阵范围 x:1000, y:1000 } var z = 20000; //生成点数 var rand = Math.random; //已经存在的点 var d = { x:[], y:[] }; for(var i=0;i<z;i++){ var _r = { x:Math.ceil(rand()*(j.x/2)), y:Math.ceil(rand()*(j.y/2)) } if(rank(_r.x,d.x) == -1 || rank(_r.y,d.y) == -1){ d.x.push(_r.x); d.y.push(_r.y); result.push(_r); }else{ i--; } } console.log(result,new Date().getTime()-_startTime);
楼主 我用js写的,测得结果是:
是直接生成随机数,再通过二分查找确定重复情况,如果x或者y有任意一个不重复则是不重复的点。