您将获得一个整数数组。您必须输出最大范围,以便该范围内的所有数字都存在于数组中。这些数字可能以任何顺序出现。例如,假设数组是
{2, 10, 3, 12, 5, 4, 11, 8, 7, 6, 15}
这里我们找到两个(非平凡的)范围,这些范围中的所有整数都存在于数组中,即[2,8]和[10,12]。其中[2,8]是较长的一个。所以我们需要输出它。
当我收到这个问题时,我被要求在线性时间内完成此操作而不使用任何排序。我认为可能存在基于散列的解决方案,但我无法想出任何东西。
这是我尝试解决方案:
void printRange(int arr[])
{
int n=sizeof(arr)/sizeof(int);
int size=2;
int tempans[2];
int answer[2];// the range is stored in another array
for(int i =0;i<n;i++)
{
if(arr[0]<arr[1])
{
answer[0]=arr[0];
answer[1]=arr[1];
}
if(arr[1]<arr[0])
{
answer[0]=arr[1];
answer[1]=arr[0];
}
if(arr[i] < answer[1])
size += 1;
else if(arr[i]>answer[1]) {
initialize tempans to new range;
size2=2;
}
else {
initialize tempans to new range
}
}
//I have to check when the count becomes equal to the diff of the range
我被困在这个部分......我无法弄清楚应该使用多少个tempanswer []数组。
答案 0 :(得分:8)
我认为以下解决方案将使用O(n)空间在O(n)时间内工作。
首先将数组中的所有条目放入哈希表中。接下来,创建第二个哈希表,它存储我们“访问过”的元素,这些元素最初是空的。
现在,一次迭代一个元素数组。对于每个元素,检查元素是否在访问集中。如果是这样,请跳过它。否则,从该元素向上计数。在每个步骤中,检查当前数字是否在主哈希表中。如果是这样,继续向前并将当前值标记为访问集的一部分。如果没有,停止。接下来,重复此过程,向下计数除外。这告诉我们包含此特定数组值的范围中的连续元素的数量。如果我们跟踪这种方式找到的最大范围,我们将解决我们的问题。
该算法的运行时复杂度为O(n)。要看到这一点,请注意我们可以在O(n)时间的第一步中构建哈希表。接下来,当我们开始扫描到阵列以找到最大范围时,扫描的每个范围花费的时间与该范围的长度成比例。由于范围长度的总和是原始数组中元素的数量,并且因为我们从不扫描相同的范围两次(因为我们标记了我们访问的每个数字),所以第二步需要O(n)时间好吧,对于O(n)的净运行时间。
编辑:如果您感到好奇,我会对此算法有 Java implementation ,并对其原理和原因进行更详细的分析它具有正确的运行时。它还探讨了一些在算法的初始描述中不明显的边缘情况(例如,如何处理整数溢出)。
希望这有帮助!
答案 1 :(得分:7)
解决方案可以使用BitSet
:
public static void detect(int []ns) {
BitSet bs = new BitSet();
for (int i = 0; i < ns.length; i++) {
bs.set(ns[i]);
}
int begin = 0;
int setpos = -1;
while((setpos = bs.nextSetBit(begin)) >= 0) {
begin = bs.nextClearBit(setpos);
System.out.print("[" + setpos + " , " + (begin - 1) + "]");
}
}
样本I / O:
detect(new int[] {2,10, 3, 12, 5,4, 11, 8, 7, 6, 15} );
[2,8] [10,12] [15,15]
答案 2 :(得分:0)
上面的模板答案可以使用,但您不需要哈希表。散列可能需要很长时间,具体取决于您使用的算法。您可以询问采访者是否有整数可以是最大数,然后创建该数量的数组。称之为存在[]然后扫描arr并标记存在[i] = 1;然后迭代遍历[]跟踪4个变量,当前最大范围的大小,当前最大范围的开始,当前范围的大小和当前范围的开始。当您看到exists [i] = 0时,比较当前范围值与最大范围值,并在需要时更新最大范围值。
如果没有最大值,则可能需要使用散列方法。
答案 3 :(得分:0)
实际上考虑到我们只对整数进行排序,因此不需要进行比较排序,您可以使用Radix-或BucketSort对数组进行排序,然后迭代它。
简单而且肯定不是受访者想要听到的内容,但仍然是正确的;)
答案 4 :(得分:0)
一个Haskell实现的Grigor Gevorgyan的解决方案,来自另一个没有机会在question之前发布的标记为重复... ...(简单地更新哈希和迄今为止最长的范围,同时遍历清单)
import qualified Data.HashTable.IO as H
import Control.Monad.Random
f list = do
h <- H.new :: IO (H.BasicHashTable Int Int)
g list (0,[]) h where
g [] best h = return best
g (x:xs) best h = do
m <- H.lookup h x
case m of
Just _ -> g xs best h
otherwise -> do
(xValue,newRange) <- test
H.insert h x xValue
g xs (maximum [best,newRange]) h
where
test = do
m1 <- H.lookup h (x-1)
m2 <- H.lookup h (x+1)
case m1 of
Just x1 -> case m2 of
Just x2 -> do H.insert h (x-1) x2
H.insert h (x+1) x1
return (x,(x2 - x1 + 1,[x1,x2]))
Nothing -> do H.insert h (x-1) x
return (x1,(x - x1 + 1,[x,x1]))
Nothing -> case m2 of
Just x2 -> do H.insert h (x+1) x
return (x2,(x2 - x + 1,[x,x2]))
Nothing -> do return (x,(1,[x]))
rnd :: (RandomGen g) => Rand g Int
rnd = getRandomR (-100,100)
main = do
values <- evalRandIO (sequence (replicate (1000000) rnd))
f values >>= print
输出:
*Main> main
(10,[40,49])
(5.30 secs, 1132898932 bytes)
答案 5 :(得分:0)
以下是Java中的解决方案:
public class Solution {
public int longestConsecutive(int[] num) {
int longest = 0;
Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
for(int i = 0; i< num.length; i++){
map.put(num[i], false);
}
int l, k;
for(int i = 0;i < num.length;i++){
if(map.containsKey(num[i]-1) || map.get(num[i])) continue;
map.put(num[i], true);
l = 0; k = num[i];
while (map.containsKey(k)){
l++;
k++;
}
if(longest < l) longest = l;
}
return longest;
}
}
其他方法here。
答案 6 :(得分:0)
我在多个平台上阅读了很多针对这个问题的解决方案,其中一个引起了我的注意,因为它非常优雅地解决了这个问题并且很容易理解。
这种方法的主干是创建一个需要O(n)时间的set / hash,从那里每次访问set / hash都将是O(1)。由于O-Notation省略了常数项,因此该算法仍可整体描述为O(n)
def longestConsecutive(self, nums):
nums = set(nums) # Create Hash O(1)
best = 0
for x in nums:
if x - 1 not in nums: # Optimization
y = x + 1 # Get possible next number
while y in nums: # If the next number is in set/hash
y += 1 # keep counting
best = max(best, y - x) # counting done, update best
return best
如果你用简单的数字跑过它,它就会直截了当。 Optimization
步骤只是一个短路,以确保您开始计数,当该特定数字是序列的beginning
时。
所有积分给Stefan Pochmann。
答案 7 :(得分:0)
使用Javascript稀疏数组功能的非常简短的解决方案:
O(n)时间,使用O(n)附加空间。
var arr = [2, 10, 3, 12, 5, 4, 11, 8, 7, 6, 15];
var a = [];
var count = 0, max_count = 0;
for (var i=0; i < arr.length; i++) a[arr[i]] = true;
for (i = 0; i < a.length; i++) {
count = (a[i]) ? count + 1 : 0;
max_count = Math.max(max_count, count);
}
console.log(max_count); // 7
答案 8 :(得分:-1)
快速完成此任务(PHP):
$tab = array(14,12,1,5,7,3,4,10,11,8);
asort($tab);
$tab = array_values($tab);
$tab_contiguous = array();
$i=0;
foreach ($tab as $key => $val) {
$tab_contiguous[$i][] = $tab[$key];
if (isset($tab[$key+1])) {
if($tab[$key] + 1 != $tab[$key+1])
$i++;
}
}
echo(json_encode($tab_contiguous));