题目一:
给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。
class Solution {
public:
vector<int> multiply(const vector<int>& A) {
vector<int> res(A.size(),0);
res[0]=1;
for(int i=1;i<A.size();i++)
{
res[i]=res[i-1]*A[i-1];
}
int temp=1;
for(int i=A.size()-2;i>=0;i--)
{
temp*=A[i+1];
res[i]*=temp;
}
return res;
}
};
剑指的思路:
B[i]的值可以看作下图的矩阵中每行的乘积。
下三角用连乘可以很容求得,上三角,从下向上也是连乘。
因此我们的思路就很清晰了,先算下三角中的连乘,即我们先算出B[i]中的一部分,然后倒过来按上三角中的分布规律,把另一部分也乘进去。
题目二:
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
方案一:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
bool * flag= new bool[length]();
for(int i=0;i<length;i++)
{
if(flag[numbers[i]]==1){
*duplication=numbers[i];
return 1;
}
flag[numbers[i]]=1;
}
delete []flag;
return 0;
}
};
此方案需要提供额外的空间来记录。
方案二:
class Solution {
public:
// Parameters:
// numbers: an array of integers
// length: the length of array numbers
// duplication: (Output) the duplicated number in the array number
// Return value: true if the input is valid, and there are some duplications in the array number
// otherwise false
bool duplicate(int numbers[], int length, int* duplication) {
for(int i=0;i<length;i++)
{
int temp=numbers[i]>=length? numbers[i]-length:numbers[i];
if(numbers[temp]>=length)
{
*duplication=temp;
return 1;
}
numbers[temp]=numbers[temp]+length;
}
return 0;
}
};
此方案充分利用了题中的信息,在原数组中进行标记。
不过也会存在一些问题:
如果 numbers[index] + length 非常大,溢出了怎么办?
inwhites :
这样写不对,你改变了数组中的值,本题有一个条件就是数组中的数从0-n-1,如果数组中出现大于n的数就是不合格的数组,要返回false,你这样加一个长度会导致分不清是原数组是不是有问题
用减去length比较好,不会溢出
whatname :
不管是加length还是减length都有问题,乘以-1肯定没有问题,可以看我的回答哈~
题目三:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
方案一(暴力求解):
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int length =data.size();
if(length<2) return;
bool num=0;
for(int i=0;i<length;i++)
{
int j=0;
for(;j<length;j++)
{
if(i!=j&&data[j]==data[i])
break;
}
if(j==length&&num==0){
*num1=data[i];
num=1;
}
else if(j==length&&num==1)
{
*num2=data[i];break;
}
}
}
};
方案二(记录表):
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
map<int ,int> record;
for(int i=0;i<data.size();i++)
record[data[i]]++;
bool num=0;
for(int i=0;i<data.size();i++){
if(record[data[i]]==1&&num==0) {*num1=data[i]; num=1;}
else if(record[data[i]]==1&&num) {*num2=data[i]; break;}
}
}
};
方案三(位运算):
首先:位运算中异或的性质:两个相同数字异或=0,一个数和0异或还是它本身。
当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。
依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。
class Solution {
public:
int AllXor(vector<int>& data){
int res=0;
for(int i=0;i<data.size();i++){
res^=data[i];
}
return res;
}
int Find1Pos(int towXor){
int res=1;
while((res&towXor)==0)
res=res<<1;
return res;
}
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int towXor=AllXor(data);
int pos1=Find1Pos(towXor);
*num1=0;*num2=0;
for(int i=0;i<data.size();i++)
{
if((data[i]&pos1)==0)
*num1^=data[i];
else
*num2^=data[i];
}
}
};
参考;https://www.nowcoder.com/profile/8898732/codeBookDetail?submissionId=19309621