所以,我经历了一些编码问题,并坚持了很长一段时间,在谷歌上进行大量研究,通过不同的帖子和门户网站,我已经理解了这个问题。会尽量简单地解释它。
该问题有 3 种解决方案:
-
使用HashMap:但正如我们所知,这将增加O(N)空间的复杂性,我们不希望这样。但是为了理解一点点,方法是迭代数组,获取数字的计数并将其保存在map中。然后迭代地图,其中计数为 1,这将是您的答案。
-
使用按位运算符:此方法的逻辑是以位为单位思考数字,然后将每个位置的所有位相加。因此,在相加后,您将看到总和是3的倍数或3 + 1的倍数(因为另一个数字只出现一次)。在此之后,如果在此和上做一个模,你将得到结果。通过这个例子,你会更好地理解。
示例:数组 - [5, 5, 5, 6]
5 以位表示: 101
6 以位表示: 110
[ 101, 101, 101, 110] (值的二进制重整)
添加到特定位置后,我们将有
第 0 个 -> 3, 第 1 个 -> 1, 第 2 个 -> 4
,如果按 3 mod,它将变成
0th -> 0, 1th -> 1, 2nd -> 1
,十进制表示是我们的答案6。
现在我们需要编写相同的代码。我已经使用注释解释了代码。
public class SingleNumberII {
/*
* Because the max integer value will go upto 32 bits
* */
private static final int INT_SIZE = 32;
public int singleNumber(final int[] A) {
int result = 0;
for(int bitIterator = 0; bitIterator < INT_SIZE; bitIterator++) {
int sum = 0, mask = (1 << bitIterator);
/*
* Mask:
* 1 << any number means -> it will add that number of 0 in right of 1
* 1 << 2 -> 100
* Why we need mask? So when we do addition we will only count 1's,
* this mask will help us do that
* */
for(int arrIterator = 0; arrIterator < A.length; arrIterator++) {
/*
* The next line is to do the sum.
* So 1 & 1 -> 0
* 1 & 0 -> 0
* The if statement will add only when there is 1 present at the position
* */
if((A[arrIterator] & mask) != 0) {
sum++;
}
}
/*
* So if there were 3 1's and 1 0's
* the result will become 0
* */
if(sum % 3 == 1) {
result |= mask;
}
}
/*So if we dry run our code with the above example
* bitIterator = 0; result = 0; mask = 1;
* after for loop the sum at position 0 will became 3. The if
* condition will be true for 5 as - (101 & 001 -> 001) and false for 6
* (110 & 001 -> 000)
* result -> 0 | 1 -> 0
*
* bitIterator = 1; result = 0; mask = 10;
* after for loop the sum at position 1 will became 1. The if
* condition will be true for 6 as - (110 & 010 -> 010) and false for 5
* (101 & 010 -> 000)
* result -> 00 | 10 -> 10
*
* bitIterator = 2; result = 10; mask = 100;
* after for loop the sum at position 2 will became 4. The if
* condition will be true for 6 as - (110 & 100 -> 100) and true for 5
* (101 & 100 -> 100)
* result -> 10 | 100 -> 110 (answer)
* */
return result;
}
}
正如我们所看到的,这不是最好的解决方案,因为我们没有必要迭代它超过32次,它也不是那么普遍。这使得访问我们的下一个方法。
-
使用按位运算符(优化和通用):
因此,对于此方法,我将尝试解释该方法,然后编写代码,然后如何使其泛化。我们将采用2个标志(一个,两个)作为类比,将它们视为集合。因此,我们该数字第一次出现,只有当它不存在于两次时,它才会被加在一个中。我们将对两个执行相同的操作,这意味着如果数字第二次出现,我们将从1中删除它,然后将其添加到两个(仅当它不存在于一个中时),并且对于第三次出现的数字,它将从第二个集合中删除,并且将不再存在于任何一个集合中。你可能会有一个问题,为什么2个集合(或变量)原因在第4点解释。
public int singleNumberOptimized(int[] A) {
int one = 0, two = 0;
/*
* Two sets to maintain the count the number has appeared
* one -> 1 time
* two -> 2 time
* three -> not in any set
* */
for(int arrIterator = 0; arrIterator < A.length; arrIterator++){
/*
* IF one has a number already remove it, and it does not have that number
* appeared previously and it is not there in 2 then add it in one.
* */
one = (one ^ A[arrIterator]) & ~two;
/*
* IF two has a number already remove it, and it does not have that number
* appeared previously and it is not there in 1 then add it in two.
* */
two = (two ^ A[arrIterator]) & ~one;
}
/*
* Dry run
* First Appearance : one will have two will not
* Second Appearance : one will remove and two will add
* Third Appearance: one will not able to add as it is there in two
* and two will remove because it was there.
*
* So one will have only which has occurred once and two will not have anything
* */
return one;
}
-
如何更通用地解决这类问题?
需要创建的集合数取决于 k 的值(每隔一个整数的外观)。m >= log(K).(计算数组中 1 的数目,以便每当计数的 1 数达到某个值(例如 k)时,计数将返回零并重新开始。为了跟踪到目前为止我们遇到的1的数量,我们需要一个计数器。假设计数器有 m 位。m 将是我们需要的集合数。
对于其他所有内容,我们都使用相同的逻辑。但是等一下我应该返回什么,逻辑是对所有集合执行OR操作,这些集合最终将在单个数字上进行OR操作,其中包含自身和一些0,这些0将实习生到单个数字。为了更好地理解这个特定的部分,请在此处阅读这篇文章。
我已经尽力向您解释解决方案。希望你喜欢它。
#HappyCoding
有关更多此类内容,请参阅: https://thetechnote.web.app/