某公司笔试题……关于数组的分组算法

tdy_nju 2017-03-08 02:25:51
刚刚参加了国内某著名IT公司的编程测验,感觉有点怀疑人生了
题目如下:写一个函数,输入是一个整数数组,输出是一个布尔值,判断这个整数数组能不能四等分。什么是四等分呢?简单说,就是在这个数组里面找到三个下标,这三个下标对应的数把数组分成四个部分,这四个部分和是相等的,那么这个数组就是可以四等分的。例如:1,1,1,2,0,2,5,-1,3,找到三个下标2,4,6分成的四个部分是{1,1},{2},{2},{-1,3},这四个部分和都是2,所以这个数组是可以四等分的,暂且认为如果四个部分有一个部分是空的话和就是0,比如可以认为{1,1,1}这个数组可以四等分(这一个要求我记得不是很清楚了,其实不是很重要)。
数组长度十万以内,数组里的每个数范围正负十万之间,要求:时间复杂度O(N)以内,空间复杂度O(N)以内,N是数组长度
...全文
2144 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
三仙半 2017-07-14
  • 打赏
  • 举报
回复
抱歉,上面的算法有问题,二等分完毕后,即使左右两边都可以二等分,也还需要比较左半部分的二等分和与右半部分二等分和是否相等
三仙半 2017-07-14
  • 打赏
  • 举报
回复
上面有错字,将二等分的想法时,“第一”那行中的“中点”应为“终点”
三仙半 2017-07-14
  • 打赏
  • 举报
回复
我的思路是先做二等分,如果可以,再做左右两部分的二等分。 做二等分的方法有起点索引s和终点索引e两个参数,方法原理如下: 第一,让左边的和L等于起点元素,右边的和R等于中点元素; 第二,让i=s,j=e 第三,L加上它右边的元素(记为Li),R加上左边的元素(记为Rj),分别计算Li-R(记为Di)和L-Rj(记为Dj),取Di和Dj中的绝对值的小者,决定增加i还是减少j,这个过程是贪心的,总是保持左右两边的和差值最小。 通过3次调用二等分方法就可以确定输入数组是否可以四等分,并且可以获得分界元素的索引。

/**
 * @author ZhengYesheng
 */
public class QuarteringDemo
{

	private int[] data;

	public QuarteringDemo(int[] data)
	{
		this.data = data;
	}

	public int[] quartering()
	{
		int mid, left, right;
		mid = halve(0, data.length - 1);
		if (mid == -1)
		{
			return null;
		}
		else
		{
			System.out.println("mid=" + mid);
			left = halve(0, mid - 1);
			if (left == -1)
			{
				return null;
			}
			else
			{
				System.out.println("left=" + left);
				right = halve(mid + 1, data.length - 1);
				if (right == -1)
				{
					return null;
				}
				else
				{
					System.out.println("right=" + right);
					int[] res = { left, mid, right };
					return res;
				}
			}
		}
	}

	private int halve(int s, int e)
	{
		int left = data[s];
		int right = data[e];
		int i = s, j = e;
		while (j - 1 > i + 1)
		{
			// 优先选取可以使左右两边的和的差值减小的元素
			int li = left + data[i + 1];
			int di = Math.abs(li - right);
			int rj = right + data[j - 1];
			int dj = Math.abs(left - rj);

			if (di > dj)
			{
				j--;
				right += data[j];
			}
			else
			{
				i++;
				left += data[i];
			}
		}
		if (left == right)
		{
			return j - 1;
		}
		else
		{
			return -1;
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		int count = 15;
		for (int i = 0; i < 100; i++)
		{
			int[] data = new int[count];
			for (int j = 0; j < count; j++)
			{
				int rnd = (int) Math.floor(Math.random() * 10) - 5;
				data[j] = rnd;
			}
			System.out.println("---------  " + i + "  --------");
			System.out.print("数据:\t");
			printArray(data);

			QuarteringDemo demo = new QuarteringDemo(data);
			int[] res = demo.quartering();
			System.out.print("结果:\t");
			if (res != null)
			{
				printArray(res);
			}
			else
			{
				System.out.println("不能四等分");
			}
		}
	}

	public static void printArray(int[] array)
	{
		for (int i = 0; i < array.length; i++)
		{
			System.out.print(array[i] + "\t");
		}
		System.out.println();
	}
}
以上代码做过简单数据的测试,可行;用随机数据,运行多次,生成的数据就没有一次是可以四等分的。
Tony19900902 2017-07-03
  • 打赏
  • 举报
回复
用java写了一个,不知道是对是错,欢迎指正。 public static void main(String[] args) { int[] aa = {1, 1, 1, 2, 0, 2, 5, -1, 3}; split(aa); } public static void split(int[] intArray) { ArrayList<Integer> list = new ArrayList<>(4); int fenxiabiao = 0; //f为假设第一个分割符下标位置 for (int f = 1; f < intArray.length - 3; f++) { list.add(f); //计算分割符之前数字之和 int sum = 0; for (int j = 0; j < f; j++) { sum += intArray[j]; } //依次计算下个分割符号位置 int sum2 = 0; //从计算下标的后一个元素开始计算和 for (int j = f + 1; j < intArray.length; ) { sum2 += intArray[j]; if (fenxiabiao <= 3) { if (sum == sum2) { //下一个元素为分割符下标 fenxiabiao++; list.add(j + 1); sum2 = 0; //跳过分割元素,继续求和 j = j + 2; } else { j++; } } else { j++; } } if (fenxiabiao == 4) { list.remove(3); list.stream().forEach(System.out::println); break; } else { list.clear(); } } }
leeky 2017-06-20
  • 打赏
  • 举报
回复
用随机数测试,难以找到符合的
procedure TForm2.btnTest2Click(Sender: TObject);
var
  idx : Integer;
  sStr : string;
begin
  ValueCnt := 100; //15 + Random(10);
  sStr := '个数:' + IntToStr(ValueCnt) + ',值=' ;
  for idx  := 1 to ValueCnt do
  begin
    iArrayValue[idx] := Random(20);
    sStr := sStr + IntToStr(iArrayValue[idx])+ ',';
  end;
  Memo1.Lines.Add(sStr);

  btnSearchClick(nil);
end;
测试数据(随机生成)之一,前后两组相等: 数:100,值=14,1,1,1,2,15,16,7,12,8,14,9,6,16,16,2,1,1,1,3,13,4,11,5,7,16,6,6,13,13,18,6,9,5,15,14,11,14,8,10,11,17,13,2,9,8,2,1,10,13,1,18,16,13,18,5,14,14,9,13,3,4,18,7,2,19,6,1,2,17,11,13,2,13,0,6,18,10,6,8,18,6,7,9,1,17,15,3,18,9,2,17,8,4,16,11,2,12,18,10, b:10,e:94 b:13,e:90 b:23,e:84 b:25,e:82 b:30,e:77 b:33,e:73 b:37,e:69 b:44,e:58 无解!
leeky 2017-06-20
  • 打赏
  • 举报
回复
关键的代码就二十多行
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm2 = class(TForm)
    btnSearch: TButton;
    Memo1: TMemo;
    btnInit: TButton;
    btnTest: TButton;
    procedure btnSearchClick(Sender: TObject);
    procedure btnTestClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;
  iArrayValue: array[1..2000] of Integer;   //待处理的数组
  ValueCnt: Integer;   //实际元素个数

implementation

{$R *.dfm}

function GetSum(bIdx, eIdx: Integer): Integer;
var
  idx: Integer;
  tmpSum: Integer;
begin
  tmpSum := 0;
  for idx := bIdx to eIdx do
    tmpSum := tmpSum + iArrayValue[idx];

  Result := tmpSum;
end;

procedure TForm2.btnSearchClick(Sender: TObject);
var
  idxB: Integer;
  idxE: Integer;
  idxM: Integer;
  SumPre, SumEnd: Integer;
  SumM1, SumM2: Integer;
  Cnt: Integer;
begin
  Cnt := ValueCnt;
  for idxB := 2 to Cnt - 5 do
  begin
    SumPre := GetSum(1, idxB - 1);
    for idxE := Cnt - 1 downto idxB + 4 do
    begin
      SumEnd := GetSum(idxE + 1, Cnt);
      if SumPre = SumEnd then
      begin
        for idxM := idxB + 2 to idxE - 2 do
        begin
          SumM1 := GetSum(idxB + 1, idxM - 1);
          if SumM1 = SumPre then
          begin
            SumM2 := GetSum(idxM + 1, idxE - 1);
            if SumM1 = SumM2 then
            begin
              Memo1.Lines.Add('位置:' + inttostr(idxB) + ',' + inttostr(idxM) + ',' + inttostr(idxE));
              Exit;
            end;
          end;
        end;
      end;
    end;
  end;
end;

procedure TForm2.btnTestClick(Sender: TObject);
begin
  ValueCnt := 9;
  iArrayValue[1] := 1;
  iArrayValue[2] := 1;
  iArrayValue[3] := 1;
  iArrayValue[4] := 2;
  iArrayValue[5] := 7;
  iArrayValue[6] := 2;
  iArrayValue[7] := 5;
  iArrayValue[8] := -1;
  iArrayValue[9] := 3;
end;

end.
leeky 2017-06-12
  • 打赏
  • 举报
回复
只为求解的话,倒很简单,要求复杂度,还没想清。 最直观的想法是从头尾向中间包围的方式:第一个分隔符从第二个元素起,计算前面数组项的和,第三个分隔符从n-1起,依次计算和,若与第一个和相等,然后取中间分隔符位置,计算并比较,…… 代码在我工作电脑,得空时附上,经过测试。
baidu_38487648 2017-05-20
  • 打赏
  • 举报
回复
以下是用PHP实现的方法:复杂度O(M*N) 
首先来讲讲思路:比如有如下满足条件的数组$arr =[1,3,1,3,1,3,1,3,4,4],长度为10,默认数组两头之外为0,首先我们把这个数组分成3份(左边,中间,右边),其中,左边 = 右边,比如这样[0], 1, [3,1,3,1,3,1,3,4,],4, [0] 又或者是这样[1,3] ,1,[3,1,3,1,3],4,[4],加粗的数字是从数组抽离的隔离点,是不纳入区间求和范围的,这点要注意。我们分成左中右后呢,接下来就是把中间那部分也分成两部分,比如以上的例子,可以是 
[0], 1, [3,1],3,[1,3,]1,[3,4,],4, [0] , 
也可以是这样的: 
[1,3] ,1,[3,1,],3,[1,3],4,[4]。其中只有后者才能满足条件。废话不多,首先我们来写一个分割中间那部分的方法,如以下的 
div2Pairs(),首先我们得把中间这一段攫取下来,传入左右两个分界点,两个分解点往中间挤一挤,比如上面的 
1,[3,1,3,1,3],4 ,挤掉分解点后,就只剩下[3,1,3,1,3]。现在要把[3,1,3,1,3]分成两等份(如果可以等份),因为我们必须保留一个分解点,所以不能通过求总和折半的方式,为了保证尽可能的分成两等份,我们可以分别从两头开始,假设从左边开始的和为lsum,右边开始的为rsum ,那么我们应该确保每一步操作中总有|lsum−rsum|是最小的,以避免错过任何一个可能的lsum==rsum,以下为这个方法具体实现:

<?php
/**
      * [div2pairs divide the array into two group ]
      * @param  int    $avg        [dynamic average]
      * @param  int    $ldeliIndex [the left delimeter]
      * @param  array  &$array     [the array to divide by lsum compared rsum]
      * @param  int    $rdeliIndex [the right delimeter]
      * @return [mixed]             [if true return the middle delimeter,or false]
      */
 public function div2pairs(int $avg,int $ldeliIndex,array&$array,int $rdeliIndex){
          $lstart = $ldeliIndex+1;  //the index where begin to calculate the sum from left;
          $rstart = $rdeliIndex-1;  //the index where begin to calculate the sum from right;
          $lsum = $array[$lstart]; //init the $lsum
          $rsum = $array[$rstart]; //init the $rsum
          $gap = $lsum-$rsum;
          while($lstart<$rstart){   //although within two 'while' but its time complexity is truely o(n); 
             while($lsum>$rsum && $lstart<$rstart-2){ //here the number 2 means that there must be 
                    $rsum+=$array[--$rstart];                 //a delimeter index can't not put into calculate
                    if($lsum-$rsum>$gap && $lstart<$rstart-2){ //avoid the gap being bigger;
                         $lsum+=$array[--$rstart]; 
                    }                                   
             }
             while ($lsum<$rsum && $lstart<$rstart-2) {
                    $lsum+=$array[++$lstart]; 
                    if($lsum-$rsum<$gap && $lstart<$rstart-2){
                         $rsum+=$array[--$rstart];
                    }
                    $gap = $lsum-$rsum;
             }
             if($rsum==$lsum){
                 if($rstart ==$lstart+2){
                     if($rsum ==$avg) //true return the dividing delimeter 
                      return $lstart+($rstart-$lstart)/2;
                     else
                      return false;   
                 }else{
                    ++$lstart; //you can also change these two lines like this:
                     $lsum+=$array[$lstart];  //--$rstart;$rsum+=$array[$rstart]
                 }
             }else{
                    if($lsum<$rsum){ //here and 'while' is used to make the $lsum and $rsum more close;
                      ++$lstart;
                     $lsum+=$array[$lstart];
                    }else{
                      --$rstart;
                      $rsum +=$array[$rstart];
                    } 
              }
           $gap = $lsum-$rsum;  //upgrade the gap between $lsum and $rsum;
          }
          return false;
     }

但是在拆分中间那部分时,我们需要先确保,左边 = 右边($lsum ==$rsum),确保动态的可能是最终结果的区间和$avg,我们使用与div2Pairs()里相类似的方式,两头开工,获取$lsum ==$rsum==$avg使他们相对应的两个分解点($ldelimeter 和 $rdelimeter),然后代入div2Pair()就可以了。
但是由于所有的m个可能的div2Pair()都需要用到,所以我们不能每次都去求一边,我们可以先用一个数组$lsumArray 先把$lsum所有下标都村起来,以方便$rsum动态调用。以下的div4Pairs()将数组四等分返回左中右三个分界点,或不能等分返回false;

      /**
       * [div4pairs divide the array into 4 pairs with delimeter]
       * @param  array  $array [array to divide]
       * @return [mixed]        [if true then return an array cluding all delimeter]
       */
     public function div4pairs(array$array){
         $length = count($array); //get the lengt of the array;
         if($length<5) return false; //because divide into 4 equals with delimeter
         $lsumArray = []; //array to store the lsum which calculate from 0;
         $lsumArray[0][] = -1; //$lsumArray[$lsum] = index, if index<0 ,default -1 
         $end = $length-2; //the 4th pair must be >=0,default $array[$length] = 0 as well as the 
                                     //$array[-1] = 0,thought they do not exist
         for ($i = 0,$lsum = 0; $i < $end; ++$i) {  
             $lsum+=$array[$i];      
             $lsumArray[$lsum][] = $i;  //store the index for each lsum;
         }
         for($j = $length-1,$rsum = 0;$j>3;--$j){ //from right to left ,calculate the rsum;
            if(isset($lsumArray[$rsum])){         //
               while(false!==current($lsumArray[$rsum])){
                  $ldeliIndex = current($lsumArray[$rsum])+1;
                  if($ldeliIndex>$j-4) break;   //3 elements between ldelimeter and rdelimeter($j);
                  if(($mid=self::div2pairs($rsum,$ldeliIndex,$array,$j))) //try to divide array into 4 equals
                    return [$ldeliIndex,$mid,$j]; //true then return these three delimeters index;
                 next($lsumArray[$rsum]); 
               }
            }
            $rsum+=$array[$j]; 
         }
        return false;
     }
baidu_38487648 2017-05-20
  • 打赏
  • 举报
回复
#12代码的不少地方写漏写错了,有问题,重新发一遍修复后的
以下是用PHP实现的方法:复杂度O(M*N) 
首先来讲讲思路:比如有如下满足条件的数组$arr =[1,3,1,3,1,3,1,3,4,4],长度为10,默认数组两头之外为0,首先我们把这个数组分成3份(左边,中间,右边),其中,左边 = 右边,比如这样[0], 1, [3,1,3,1,3,1,3,4,],4, [0] 又或者是这样[1,3] ,1,[3,1,3,1,3],4,[4],加粗的数字是从数组抽离的隔离点,是不纳入区间求和范围的,这点要注意。我们分成左中右后呢,接下来就是把中间那部分也分成两部分,比如以上的例子,可以是 
[0], 1, [3,1],3,[1,3,]1,[3,4,],4, [0] , 
也可以是这样的: 
[1,3] ,1,[3,1,],3,[1,3],4,[4]。其中只有后者才能满足条件。废话不多,首先我们来写一个分割中间那部分的方法,如以下的 
div2Pairs(),首先我们得把中间这一段攫取下来,传入左右两个分界点,两个分解点往中间挤一挤,比如上面的 
1,[3,1,3,1,3],4 ,挤掉分解点后,就只剩下[3,1,3,1,3]。现在要把[3,1,3,1,3]分成两等份(如果可以等份),因为我们必须保留一个分解点,所以不能通过求总和折半的方式,为了保证尽可能的分成两等份,我们可以分别从两头开始,假设从左边开始的和为lsum,右边开始的为rsum ,那么我们应该确保每一步操作中总有|lsum−rsum|是最小的,以避免错过任何一个可能的lsum==rsum,以下为这个方法具体实现:

<?php
/**
      * [div2pairs divide the array into two group ]
      * @param  int    $avg        [dynamic average]
      * @param  int    $ldeliIndex [the left delimeter]
      * @param  array  &$array     [the array to divide by lsum compared rsum]
      * @param  int    $rdeliIndex [the right delimeter]
      * @return [mixed]             [if true return the middle delimeter,or false]
      */
 public function div2pairs(int $avg,int $ldeliIndex,array&$array,int $rdeliIndex){
          $lstart = $ldeliIndex+1;  //the index where begin to calculate the sum from left;
          $rstart = $rdeliIndex-1;  //the index where begin to calculate the sum from right;
          $lsum = $array[$lstart]; //init the $lsum
          $rsum = $array[$rstart]; //init the $rsum
          $gap = $lsum-$rsum;
          while($lstart<$rstart){   //although within two 'while' but its time complexity is truely o(n); 
             while($lsum>$rsum && $lstart<$rstart-2){ //here the number 2 means that there must be 
                    $rsum+=$array[--$rstart];                 //a delimeter index can't not put into calculate
                    if($lsum-$rsum>$gap && $lstart<$rstart-2){ //avoid the gap being bigger;
                         $lsum+=$array[++$lstart];  
                    }
                    $gap = $lsum-$rsum;                                     
             }
             while ($lsum<$rsum && $lstart<$rstart-2) {
                    $lsum+=$array[++$lstart]; 
                    if($lsum-$rsum<$gap && $lstart<$rstart-2){
                         $rsum+=$array[--$rstart];
                    }
                    $gap = $lsum-$rsum;
             }
             if($rsum==$lsum){
                 if($rstart ==$lstart+2){
                     if($rsum ==$avg) //true return the dividing delimeter 
                      return $lstart+($rstart-$lstart)/2;
                     else
                      return false;   
                 }else{
                    ++$lstart; //you can also change these two lines like this:
                     $lsum+=$array[$lstart];  //--$rstart;$rsum+=$array[$rstart]
                 }
             }else{
                    if($lsum<$rsum){ //here and 'while' is used to make the $lsum and $rsum more close;
                      ++$lstart;
                     $lsum+=$array[$lstart];
                    }else{
                      --$rstart;
                      $rsum +=$array[$rstart];
                    } 
              }
           $gap = $lsum-$rsum;  //upgrade the gap between $lsum and $rsum;
          }
          return false;
     }

但是在拆分中间那部分时,我们需要先确保,左边 = 右边($lsum ==$rsum),确保动态的可能是最终结果的区间和$avg,我们使用与div2Pairs()里相类似的方式,两头开工,获取$lsum ==$rsum==$avg使他们相对应的两个分解点($ldelimeter 和 $rdelimeter),然后代入div2Pair()就可以了。
但是由于所有的m个可能的div2Pair()都需要用到,所以我们不能每次都去求一边,我们可以先用一个数组$lsumArray 先把$lsum所有下标都村起来,以方便$rsum动态调用。以下的div4Pairs()将数组四等分返回左中右三个分界点,或不能等分返回false;

      /**
       * [div4pairs divide the array into 4 pairs with delimeter]
       * @param  array  $array [array to divide]
       * @return [mixed]        [if true then return an array cluding all delimeter]
       */
     public function div4pairs(array$array){
         $length = count($array); //get the lengt of the array;
         if($length<5) return false; //because divide into 4 equals with delimeter
         $lsumArray = []; //array to store the lsum which calculate from 0;
         $lsumArray[0][] = -1; //$lsumArray[$lsum] = index, if index<0 ,default -1 
         $end = $length-2; //the 4th pair must be >=0,default $array[$length] = 0 as well as the 
                                     //$array[-1] = 0,thought they do not exist
         for ($i = 0,$lsum = 0; $i < $end; ++$i) {  
             $lsum+=$array[$i];      
             $lsumArray[$lsum][] = $i;  //store the index for each lsum;
         }
         for($j = $length-1,$rsum = 0;$j>3;--$j){ //from right to left ,calculate the rsum;
            if(isset($lsumArray[$rsum])){         //
               while(false!==current($lsumArray[$rsum])){
                  $ldeliIndex = current($lsumArray[$rsum])+1;
                  if($ldeliIndex>$j-4) break;   //3 elements between ldelimeter and rdelimeter($j);
                  if(($mid=self::div2pairs($rsum,$ldeliIndex,$array,$j))) //try to divide array into 4 equals
                    return [$ldeliIndex,$mid,$j]; //true then return these three delimeters index;
                 next($lsumArray[$rsum]); 
               }
            }
            $rsum+=$array[$j]; 
         }
        return false;
     }


以下这个是最常规的方法,简单一目了然。空间复杂度O(N) 时间复杂度O(N^2)
     /**
      * [div4pairsF another simple method to divide array into 4 equals with excluding delimeter index]
      * @param  array  $array [array to divide]
      * @return [mixed]        [if true return delimeters index,or false]
      */
     public function div4pairsF(array$array){
          $length = count($array);
          $ilength = $length-4;
          $jlength = $length-2;
          for ($i=0,$isum = 0;$i < $ilength; ++$i) { 
              for ($j=$i+1,$jsum = 0; $j < $jlength; ++$j) { 
                      $jsum+=$array[$j];
                      if($jsum==$isum){
                        ++$j;
                          for($k = $j+1,$ksum = 0;$k<$length;++$k){
                              $ksum+=$array[$k];
                              if($ksum==$isum){
                                 ++$k;
                                  if($k+1<$length){
                                     for ($n=$k+1,$nsum=0; $n < $length; ++$n) { 
                                         $nsum+=$array[$n];
                                     }
                                     if($nsum==$isum) 
                                       return [$i,$j,$k];
                                  }
                              }
                          }
                      }
              }
              $isum+=$array[$i];
          }
          return false;
     }

         public function createTestingData(int $m){
             for ($i=0,$data=[]; $i < $m; ++$i) { 
                 $in = mt_rand(-$m,$m);
                    $data[] = $in;
            }
            return $data; 
         }

check:
$all = [1,2,5,4,-1];  // false
$all = [1,-1,2,-1,4,-3,4,2,1];  //array(3) { [0]=> int(1) [1]=> int(4) [2]=> int(7) }
$all = [1,3,1,3,1,3,1,3,4,4];  //Array ( [0] => 2 [1] => 5 [2] => 8 )
// $res = AlgorithmicTest::div4pairsF($all);
$res = AlgorithmicTest::div4pairs($all);  
print_r($res);

测试两种方法

$n = 100;//1000,10000,100000,1000000
$all = AlgorithmicTest::createTestingData($n);
echo memory_get_usage(),'<br>';
$s = microtime(true);
$res = AlgorithmicTest::div4pairs($all); 
// $res = AlgorithmicTest::div4pairsF($all);
echo 'times:      ',microtime(true)-$s,'<br>';
echo memory_get_peak_usage(),'<br>';

结果:
memory:byte times:s

div4pairsF($all) n=100
memory used before processing:447216
times: 0.00018191337585449
memory used_peak in processin: 612104

div4pairs($all)n=100
memory used before processing:447176
times: 6.9141387939453E-5
memory used_peak in processin: 612104

div4pairsF($all) n=1000
memory used before processing:475888
times: 0.010547161102295
memory used_peak in processin: 612104

div4pairs($all) n=1000
memory used before processing:475848
times: 0.00043797492980957
memory used_peak in processin: 880960

div4pairsF($all) n=10000
memory used before processing:967408
times: 0.97418403625488
memory used_peak in processin: 967664

div4pairs($all)n=10000
memory used before processing:967368
times: 0.0051088333129883
memory used_peak in processin: 5293064

div4pairsF($all) n=100000 (已经阵亡!)
memory used before processing:4637448
(30s内无法完成)
Fatal error: Maximum execution time of 30 seconds exceeded in /usr/local/nginx/html/algorithmic/algorithmic_test/AlgorithmicTest.php on line 741

div4pairs($all) n=100000
memory used before processing:4637408
times: 0.089447975158691
memory used_peak in processin: 46877568

div4pairs($all) n=1000000
memory used before processing:33997536
times: 3.2110240459442
memory used_peak in processin: 447408504
baidu_38487648 2017-05-19
  • 打赏
  • 举报
回复
//以下是使用php写的代码,有兴趣的同学自己可以自行实现 // 该方法局限性:$sum不能存在重复值 // 时间:N 空间 N <?php function divGroup(array$array){ $length = count($array); for ($i=0,$sum = 0,$sums = []; $i < $length; ++$i) { $sum += $array[$i]; $sums[$sum] = $i; } if(isset($sums[$sum/4]) && isset($sums[$sum/4*2]) && isset($sums[$sum/4*3])) echo $sums[$sum/4],' ',$sums[$sum/4*2],' ',$sums[$sum/4*3]; else echo 'it is not the available array to div into 4 equal'; } echo divGroup([1,-1,1,-1,1,-1,1,-1]); // 7 7 7 这种就不能正确计算了 echo divGroup([1,3,2,2,3,1,4]); // 1,3,5 echo divGroup([1,2,3,4]); // it is not the available array to div into 4 equal
strangejie 2017-05-15
  • 打赏
  • 举报
回复
目前只想到了复杂度为o(N^2)的算法,o(N)的算法没想出来。
strangejie 2017-05-15
  • 打赏
  • 举报
回复
仔细思考了下,上面的算法错了,不能正数化。
strangejie 2017-05-14
  • 打赏
  • 举报
回复
代码写好了还没调试,先附上代码 #include<stdio.h> #include<stdlib.h> #include<string.h> #define N 100 #define RANGE 100000 int main() { double Nums[N+1]; double Sums[N+1]; int i,j,k; int n; int pairs[2*N+1]; int s1,s2; for(i=0;i<N;)/*读入数据*/ { printf("input the %d number:",i+1); scanf("%f\n",Nums[i]); if((Nums[i]>RANGE)||(Nums[i]<-RANGE)) { printf("the %d number out of range!",i+1); continue; } else { i++; } } for(i=0;i<N;i++)/*将所有的数据正数化,时间复杂度o(N)*/ { Nums[i]+=RANGE; } Sums[0]=Nums[0]; for(i=1;i<N;i++)/*Sums[i]是从Nums[0]至Nums[i]的和,这样处理的目的是便于后面的计算,时间复杂度o(N)*/ { Sums[i]=Sums[i-1]+Nums[i]; } n=0; i=0; j=N-1; while(i<j-5) { if(Sums[i]==(Sums[N-1]-Sums[j])) { pairs[2*n]=i; pairs[2*n+1]=j; n++; i++; } else if(Sums[i]<=(Sums[N-1]-Sums[j])) { i++; } else { j--; } } if(n==0) { return -1; } k=0; for(i=0;i<n;i++) { s1=pairs[2*i]; s2=pairs[2*i+1]; if(k>=s2-3) { break; } if((s1+2)>=k) { k=s1+2; } for(;;k++)/*这部分看似是o(N^2),其实只是o(N)*/ { if(Sums[k]>(Sums[s1]+Sums[s1+1])) { break; } else if(Sums[k]=(Sums[s1]+Sums[s1+1])) { if((Sum[s2-2]-Sum[k+1])==Sums[s1]) { return 0; } } } } return -1; }
棒子先生 2017-04-25
  • 打赏
  • 举报
回复
LZ 不妨想想 1 个点把数组一分为 2,如何求解
angel6709 2017-04-07
  • 打赏
  • 举报
回复
第一趟,求和,除4 得到AVG,能整除则初步判断为可均分,进入下一趟,不能整除则不能均分 第二趟,求和,如果得到AVG,在该位置打标记,sum清零继续往下求和。。。 如果碰不到AVG而超过AVG了,,不能整除则不能均分 完了 空间 N 时间 2N
oqqHui1234567891 2017-04-06
  • 打赏
  • 举报
回复
O(N)的算法复杂度 实在想不出来
oqqHui1234567891 2017-04-06
  • 打赏
  • 举报
回复
	private static HashSet<Integer> getSum(int[] array, int start, int end) {
		if (start > end) {
			return new HashSet<>();
		}
		HashSet<Integer> result = new HashSet<>();
		int sum = 0;
		for (int i = start; i <= end; i++) {
			sum = sum + array[i];
		}
		result.add(sum);
		result.add(array[start]);
		result.addAll(getSum(array, start + 1, end));
		result.add(array[end]);
		result.addAll(getSum(array, start, end - 1));
		return result;
	}
	private static boolean testArray(int[] array) {
		for (int i = 0; i <= array.length - 4; i++) {
			// 0到i内的集合
			HashSet<Integer> result1 = getSum(array, 0, i);
			for (int j = i + 1; j <= array.length - 3; j++) {
				// i+1到j的集合
				HashSet<Integer> result2 = getSum(array, i+1, j);
				for (int m = j + 1; m <= array.length - 2; m++) {
					// j+1到m的集合
					HashSet<Integer> result3 = getSum(array, j+1, m);
					for (int n = m + 1; n <= array.length - 1; n++) {
						// m+1到n的集合
						HashSet<Integer> result4 = getSum(array, m+1, n);
						//判断result1 2 3 4是否都有相同结果 是返回true
					}
				}
			}
		}

		return false;
	}
tdy_nju 2017-03-10
  • 打赏
  • 举报
回复
引用 2 楼 yyfhz 的回复:
求总和(A),均分4份(B=A/4)。 数组从前往后开始遍历求和,求到和为B时切出一块,然后对剩下部分重新求和,依次类推。 若遍历到末尾都找不到合适的段,表示无法分割,报错退出。 否则全部分完后输出分割点即可。
不对的,是要分离出分割点的,求总和除以4没有意义啊,就是能四等分的并不一定总和就是4的倍数,比如{1,3,1,3,1,3,1}你以3个3作为分割点,剩下的每个部分和都是1,这样的数组就是可以四等分的,可是求总和没有意义
yyfhz 2017-03-09
  • 打赏
  • 举报
回复
求总和(A),均分4份(B=A/4)。 数组从前往后开始遍历求和,求到和为B时切出一块,然后对剩下部分重新求和,依次类推。 若遍历到末尾都找不到合适的段,表示无法分割,报错退出。 否则全部分完后输出分割点即可。
tdy_nju 2017-03-08
  • 打赏
  • 举报
回复
当然如果有复杂度比较小的(小于N三次方的)思路也可以来指教下啊~不一定要完全符合要求 顺便说下这题的倒计时是30分钟

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧