首页 新闻 会员 周边

用PHP 如何高效生成不重复坐标点,比如在100*100 的矩阵随机生成200个坐标点

0
悬赏园豆:50 [已解决问题] 解决于 2017-08-17 20:49

去面试,有道笔试题是PHP随机生成坐标的,自己想了两种种策略(1.随机生成x,和y坐标,然后遍历去重   2.把所有坐标生成出来,然后随机取200),但感觉不是很高效,发出来看看有没有跟好的实现

PHP
北冥那条鱼的主页 北冥那条鱼 | 初学一级 | 园豆:157
提问于:2017-08-17 15:27
< >
分享
最佳答案
-2
//点反对的人,把你们的代码留下,否则就别装逼!

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环境

收获园豆:50
会长 | 专家六级 |园豆:12401 | 2017-08-17 17:10

这种方法可以,效率应该比我想的那两种好点,具体试试才知道

北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-17 20:48

刚试了下100*100的矩阵,随机取2000个坐标,这种方法耗时0.4秒多,用for循环把100*100的坐标全存在数组,然后随机取2000这种方法耗时0.01秒级别,数量级越大你说的方法效率越低,还有就是num % 100;100倍数这些求余完就是0了,还需要处理下

北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-17 21:46

@北冥那条鱼: 谢谢,看来还得试试才知道,我没有试,惭愧

会长 | 园豆:12401 (专家六级) | 2017-08-18 09:06

@北冥那条鱼: 你说的那种耗时0.01s的方法能不能贴出代码让我学习一下啊,谢谢

会长 | 园豆:12401 (专家六级) | 2017-08-18 09:09

@北冥那条鱼: 我用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; } } }
会长 | 园豆:12401 (专家六级) | 2017-08-18 09:41

@北冥那条鱼: 100的倍数求余等于0对的呀,表示纵坐标是0。100对应的坐标是(1,0)

会长 | 园豆:12401 (专家六级) | 2017-08-18 09:50

@会长: 比如说100*100的矩阵,坐标(10,200)这个点,200%100的话就是(10,0),所以需要判断下如果是0的话yCoord就应该是纵坐标纬度

北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-18 09:57

@会长: 没有没有,大家相互学习相互讨论

北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-18 10:00

@会长: 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;
}

北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-18 10:04

@北冥那条鱼: 我觉得我们好像说岔道了。我的意思是这样的:

给一个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的列表)中把它去掉,保证不会产生重复的点。

会长 | 园豆:12401 (专家六级) | 2017-08-18 10:05

@北冥那条鱼: 你这个是用了php内置函数array_rand。那可能比较高效了吧,毕竟是牛人写的函数。

会长 | 园豆:12401 (专家六级) | 2017-08-18 16:01
其他回答(3)
1

首先100*100就是10000

生成100不重复的0-10000的随机数.

百度:洗牌算法.

吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-17 16:08

这种方法我试试

支持(0) 反对(0) 北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-17 21:48
0

遇到重复的再随机一次(逃

长蘑菇星人 | 园豆:1832 (小虾三级) | 2017-08-17 16:11

这种需要不停遍历以前的数组,效率应高不会太高

支持(0) 反对(0) 北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-17 21:49

@北冥那条鱼: 并不会..你弄一个hash.每一次获取随机数后就往hash表里插入.

知道hash表的长度到你要的要求.就行了

支持(0) 反对(0) 吴瑞祥 | 园豆:29449 (高人七级) | 2017-08-18 08:30

@吴瑞祥: OK,我试试

支持(0) 反对(0) 北冥那条鱼 | 园豆:157 (初学一级) | 2017-08-18 10:06
0
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有任意一个不重复则是不重复的点。

张泰峰 | 园豆:20 (初学一级) | 2017-08-18 10:50
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册