Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/304.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何改进:给定两个整数,返回它们共享的位数_Java_Algorithm_Int_Hashtable - Fatal编程技术网

Java 如何改进:给定两个整数,返回它们共享的位数

Java 如何改进:给定两个整数,返回它们共享的位数,java,algorithm,int,hashtable,Java,Algorithm,Int,Hashtable,我在一次采访中收到了这个问题,问题是 给定两个整数,返回它们共享的位数 例如,129和431将返回1-因为它们都共享数字1,但没有其他数字。95和780将返回0,因为所有整数都不重叠 我的想法只是重复这些数字,将它们存储到哈希表中,然后检查.containsKey. 我的Java解决方案: public int commonDigits(int x, int y) { int count = 0; HashTable<Integer, String> ht = n

我在一次采访中收到了这个问题,问题是

给定两个整数,返回它们共享的位数

例如,129和431将返回1-因为它们都共享数字
1
,但没有其他数字。95和780将返回0,因为所有整数都不重叠

我的想法只是重复这些数字,将它们存储到哈希表中,然后检查
.containsKey.

我的Java解决方案:

public int commonDigits(int x, int y) {
     int count = 0;
     HashTable<Integer, String> ht = new HashTable<Integer, String>();

     while (x != 0) { 
         ht.put(x % 10, "x");
         x /= 10;
     }

     while (y != 0) {
         if ((ht.containsKey(y % 10)) {
             count++;
         }
         y /= 10;
     }

    return count;
}
public int commonDigits(int x,int y){
整数计数=0;
HashTable ht=新的HashTable();
而(x!=0){
ht.put(x%10,“x”);
x/=10;
}
而(y!=0){
如果((高温容器(y%10)){
计数++;
}
y/=10;
}
返回计数;
}

但是这会占用O(n)空间和O(n+m)时间,无论如何我可以改进这一点?

既然只有10个可能的数字,为什么不存储一个整数数组呢?索引从0到9,每个数字一个。循环每个数字并增加相应的数组元素。这的空间复杂度取决于您定义的“常量”-这将始终占用10个空间单位(在C/C++中为10个字节,不确定JVM是如何做到的)


通过信息守恒,你必须循环两个数字的每一个数字(它们是独立的,所以你不能从另一个数字中推断出一个),所以你的时间复杂度将保持在O(m+n)。我认为O(n)的意思是O(logn),因为这是数字的任何表示形式中的位数。

为什么不使用一些简单的位摆弄呢

public int commonDigits(int x, int y) {
  int dX = 0;
  while (x != 0) {
    dX |= 1 << (x % 10);
    x /= 10;
  }
  int count = 0;
  while (y != 0) {
    int mask = 1 << (y % 10);
    if ((dX & mask) != 0) {
      count ++;
      dX &= ~mask;
    }
    y /= 10;
  }
  return count;
}
这两个代码段的工作方式完全相同,后者只是对位集(和嵌入式数组)实例有更多的开销

本文介绍了在一般情况下,位集优于布尔数组的原因:

编辑

如果实际需要对同一个数字进行多次计数(问题中的示例不清楚),请使用int数组存储计数:

public int commonDigits(int x, int y) {
  int count = 0;
  int[] digits = new int[10];

  while (x != 0) { 
     digits[x % 10]++;
     x /= 10;
  }
  while (y != 0) {
     if (digits[x % 10] > 0) {
         count++;
         digits[x % 10]--;
     }
     y /= 10;
  }
  return count;
}

您的解决方案不考虑重复项

# 11, 211 -> 2
你使用散列是对的,它比数组快。在python中这样做是因为它的键入速度更快

# Returns an array containing the shared digits
def getShared(num1, num2):
    shared = []
    digits1 = getDigits(num1)
    digits2 = getDigits(num2)
    for digit in digits1:
        if digit in digits2:
            while digits2[digit] > 1 and digits1[digit] > 1:
                digits2[digit] = digits2[digit] - 1
                digits1[digit] = digits1[digit] - 1
                shared += [digit]
            del digits2[digit]
            del digits1[digit]
    return shared

# Given an integer, returns a dictionary with the keys as the digits,
# and the value as the number of times the digit appears
def getDigits(num)
    dict = {}
    while num > 0:
        newDigit = num % 10
        if newDigit not in dict:
            dict[newDigit] = 1
        else:
            dict[newDigit] = dict[newDigit] + 1
    return dict

最多可以共享10个数字。这意味着您不需要像哈希表、数组或位掩码这样的复杂数据结构就足够了

您只需在第一个数字上进行迭代,您点击的每个数字都会被标记为“true”(在您的位掩码或数组中)。您甚至可以将其短路,并在找到每个数字一次的情况下提前返回(使用位掩码既简单又便宜)。然后检查第二个数字。每次碰到标记为true的数字时,请增加计数器。如果位掩码包含每个数字,请通过返回数字的长度(其最高指数)进行短路,否则返回末尾的计数器

这并没有降低O复杂度,但它减少了内存占用,并为大量数据增加了一些短路


例如,如果第一个数字是1234567890,那么它将始终与第二个数字共享与第二个数字小数位数相同的数字。

这是具有最小存储空间的解决方案(一个10字节的数组,而不是哈希表):


该解决方案在运行时间
O(n+m)时是最佳的
,其中
n
x
中的位数,
m
y
中的位数。你只能枚举
x
的位数,那么
y
的位数就太多了,只需使用十个标志的数组(是用位运算将它们打包成一个整数,还是保留独立变量取决于您)

扫描第一个整数,并为每个数字提升相关标志

扫描第二个整数并重置每个数字的相关标志

返回真实重置次数(从1到0)

更新:要处理重复项,需要用计数器替换标志


如果两个数字都有M个数字,则必须查看它们,以便时间复杂度一定为Ω(M)

空间复杂性的情况不太清楚。这里给出的所有解决方案都是O(N),其中N是可能的位数(十进制基数为10)。但是O(1)空间是可能的:依次取第一个数字的每个数字,检查它是否是第一个数字中的第一个这样的数字(以避免重复计数),然后检查它是否存在于第二个数字中。这是一个O(M²)时间过程,但只存在O(1)空间

更新:要处理重复的数字,每次处理一个数字时,都要在第一个数字中计算相同前置数字的数量;在第二个数字中查找匹配项时,也要匹配前置数字的数量

因此,人们可能想知道O(M)-时间,O(1)-空间解是否可能


我的解决方案是O(M+N)-时间,O(N)-空间。时间复杂度中的+N仅在初始化所有N个标志时需要。如果您接受不计算初始化,您可以以这样的方式编写算法:它清除它设置的所有标志(以便可以再次播放算法),这将产生O(M)-时间,O(N)-空间解决方案



有一个简单的O(M Log M)-时间,O(M)-空间解决方案,通过对两个数字串进行排序,并在一个类似合并的步骤中计算相同的数字。如果M与N相比非常小,则可以使用此解决方案。

您可能会发现它属于on而不是ht.get(y%10)!=“y”),它不起作用(因为字符串比较)而且地图上从来没有一个
y
。是的,你是对的,我接受这一部分,即使'int[10]'就足够了……我投票结束这个问题,因为这里有codereview.stackexchange.com用于“查看工作代码”请求。非唯一数字:P se
# Returns an array containing the shared digits
def getShared(num1, num2):
    shared = []
    digits1 = getDigits(num1)
    digits2 = getDigits(num2)
    for digit in digits1:
        if digit in digits2:
            while digits2[digit] > 1 and digits1[digit] > 1:
                digits2[digit] = digits2[digit] - 1
                digits1[digit] = digits1[digit] - 1
                shared += [digit]
            del digits2[digit]
            del digits1[digit]
    return shared

# Given an integer, returns a dictionary with the keys as the digits,
# and the value as the number of times the digit appears
def getDigits(num)
    dict = {}
    while num > 0:
        newDigit = num % 10
        if newDigit not in dict:
            dict[newDigit] = 1
        else:
            dict[newDigit] = dict[newDigit] + 1
    return dict
public int commonDigits(int x, int y) {
 int count = 0;
 byte[] digits=new byte[10];

 while (x != 0) { 
     digits[x%10] ++;
     x /= 10;
 }

 while (y != 0) {
     if (digits[y % 10] > 0) {
         count++;
         digits[y % 10] --;
     }
     y /= 10;
 }

return count;
}