136.Single number [LeetCode]

136_Single_number    

Given a non-empty array of integers nums, every element appears twice except for one. Find that single one.

 You must implement a solution with a linear runtime complexity and use only constant extra space.

/*
方法一、利用位运算。
   ^ 异或运算,不同为1,相同为0;
   1^1=0;
   0^0=0;
   1^0=1;
   0^1=1;
   先转换成二进制,然后异或,3^5 → 11^101=110  → 6.   

   还有一个用途,交换两个数的值:
   a=a^b;
   b=a^b;  // b=a^b^b=a,  b^b 抵消所以a^b^b得a,实现b=a,把a赋值给b
   a=a^b;  // a=(a^b)^a,抵消之后剩余b

方法二、利用map,统计每个数字出现的次数。

方法三、先排序,和后面相邻元素比较。
*/

// bits operation
int singleNumber(int* nums, int numsSize){
    int res = 0;
    for (int i = 0; i < numsSize; i++) 
        res ^= nums[i];
    return res;
}

// map
class Solution {
public:
    int singleNumber(vector<int> &nums){
        unordered_map<int, int> cnts;    // {number, count}
        for (auto x : nums)
            cnts[x]++;
 
        for (auto x : cnts)
           if (x.second != 2)
              return x.first;

        return 0;
    }
};

// sort
class Solution_136_4 {
public:
    int singleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        for (int i = 0; i<nums.size(); i += 2)
            if (nums[i] != nums[i + 1])
                return nums[i];
        return 0;
    }
};

 

 

 

137_Single_Number II

Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

// bits operation
/**************************************************************************
 * First of all, consider the (set^val) as one of the following:
 * 1. adding "val" to the "set" if "val" is not in the "set" => A^0 = A
 * 2. removing "val" from the "set" if "val" is already in the "set" => A^A = 0
 * 
 * Assume "ones" and "twos" to be sets that are keeping track of which numbers 
 * have appeared once and twice respectively;
 * 
 * "(ones ^ A[i]) & ~twos" basically means perform the above mentioned operation 
 * if and only if A[i] is not present in the set "twos". So to write it in layman:
 * 
 *    IF the set "ones" does not have A[i]
 *        Add A[i] to the set "ones" if and only if its not there in set "twos"
 *    ELSE
 *        Remove it from the set "ones"
 * 
 * So, effectively anything that appears for the first time will be in the set. 
 * Anything that appears a second time will be removed. We'll see what happens 
 * when an element appears a third time (thats handled by the set "twos").
 * 
 * After this, we immediately update set "twos" as well with similar logic:
 * "(twos^ A[i]) & ~ones" basically means:
 * 
 *    IF the set "twos" does not have A[i]
 *        Add A[i] to the set "twos" if and only if its not there in set "ones"
 *    ELSE
 *        Remove it from the set "twos"
 * 
 * So, effectively, any number that appears a first time will be in set "ones" so 
 * it will not be added to "twos". Any number appearing a second time would have been 
 * removed from set "ones" in the previous step and will now be added to set "twos". 
 * Lastly, any number appearing a third time will simply be removed from the set "twos" 
 * and will no longer exist in either set.
 * 
 * Finally, once we are done iterating over the entire list, set "twos" would be 
 * empty and set "ones" will contain the only number that appears once.
 *************************************************************************/
int singleNumber(int* nums, int numsSize){
    int once = 0;
    int twice = 0;
    for (int i = 0; i < numsSize; i++) {
        once = once ^ nums[i] & ~twice;
        twice = twice ^ nums[i] & ~once;
    }
    return once;
}

// map
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> cnts;    // {number, count}
        for (auto x : nums)
            cnts[x]++;
 
        for (auto x : cnts)
           if (x.second != 3)
              return x.first;

        return 0;
    }
};

 

260_Single_Number_III

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

[剑指offer 40.]一个整型数组里除了两个数字之外,其他的数字都出现了两次。



/// bits operation
static unsigned int FindFirstBitIs1(int num) {
    int indexBit = 0;
    while (((num & 1) == 0) && (indexBit < 8 * sizeof(int))) {
        num = num >> 1;
        ++indexBit;
    }
    return indexBit;
}

static char IsBit1(int num, unsigned int indexBit) {
    return (num >> indexBit) & 0x1;
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* singleNumber(int* nums, int numsSize, int* returnSize){
    *returnSize = 0;
    if (nums == NULL || numsSize < 2 || returnSize == NULL) 
        return NULL;

    int *res = (int *)calloc(2, sizeof(int));
    if (res == NULL) 
        return NULL;

    *returnSize = 2;
    int resultExclusiveOR = 0;
    for (int i = 0; i < numsSize; i++) 
        resultExclusiveOR ^= nums[i];

    unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);
    
    for (int i = 0; i < numsSize; i++) {
        if (IsBit1(nums[i], indexOf1))
            res[0] ^= nums[i];
        else
            res[1] ^= nums[i];
    }

    return res;
}





///  优化上面的函数
int* singleNumber(int* nums, int numsSize, int* returnSize){
    *returnSize = 0;
    if (nums == NULL || numsSize < 2 || returnSize == NULL) 
        return NULL;
 
    long val = 0;
    for (int i = 0; i < numsSize; i++)
        val ^= nums[i];

    val &= -val;

    int *res = (int *)calloc(2, sizeof(int));
    if (res == NULL)
        return NULL;

    *returnSize = 2;
    
    for (int i = 0; i < numsSize; i++) {
        if (nums[i] & val) 
            res[0] ^= nums[i];
        else 
            res[1] ^= nums[i];
    }
    
    return res;
}





/// 使用map
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {    
        vector<int>result;
        unordered_map<int, int> cnts;    // {number, count}  
        for (auto &x : nums)
            cnts[x]++;
 
        for (auto x : cnts)
            if (x.second == 1)
                result.push_back(x.first);

        return result;
    }
};

 

575_Distribute_Candies

    Given an integer array with even length, where different numbers in this array represent different kinds of candies. Each number means one candy of the corresponding kind. You need to distribute these candies equally in number to brother and sister. Return the maximum number of kinds of candies the sister could gain.

Example 1:

Input: candies = [1,1,2,2,3,3]
Output: 3
Explanation:
There are three different kinds of candies (1, 2 and 3), and two candies for each kind.
Optimal distribution: The sister has candies [1,2,3] and the brother has candies [1,2,3], too. 
The sister has three different kinds of candies. 

Example 2:

Input: candies = [1,1,2,3]
Output: 2
Explanation: For example, the sister has candies [2,3] and the brother has candies [1,1]. 
The sister has two different kinds of candies, the brother has only one kind of candies.

 

#define MIN(a, b) ((a) < (b) ? (a) : (b))

static int cmpfunc (const void * a, const void * b) {
   return ( *(int*)a - *(int*)b );
}

int distributeCandies(int* candyType, int candyTypeSize){
    if (NULL == candyType || candyTypeSize < 2 || candyTypeSize & 1)
        return 0;
    
    qsort(candyType, candyTypeSize, sizeof(int), cmpfunc);

    int types = 1;
    for (int i = 1; i < candyTypeSize; i++) 
        if (candyType[i] != candyType[i - 1])
            types++;

    return MIN(types, candyTypeSize/2);
}


//map
class Solution {
public:
    int distributeCandies(vector<int>& candyType) {
        int res = 0;
        if (candyType.size() < 2 || candyType.size() & 0X1)
			return res;
        
        unordered_map<int, int> cnts;    // {number, count}
        for (auto &x : candyType) {
            cnts[x]++;
            if (cnts[x] == 1 && res < candyType.size() / 2)
                res++;
        }
        return res;
    }
};


//set
int distributeCandies2(vector<int>& candies) {
    return min(unordered_set<int>(candies.cbegin(), candies.cend()).size(), candies.size() / 2);
}

 

1_Two_Sum

    Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

 



/// 解法一 C++
vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map<int, int> _map;
    vector<int>result;
    for (auto i = 0; i != nums.size(); ++i)
        _map[nums[i]] = i;

    for (auto i = 0; i != nums.size(); ++i) {
        const int gap = target - nums[i];
        if (_map.find(gap)!= _map.end() && _map[gap] > i) {
            result.push_back(i);
            result.push_back(_map[gap]);
        }
    }
    return result;
}



/// 解法二 C
typedef struct _MAP_ {
    int num;
    int index;
} MAP;

static int cmpfunc (const void * a, const void * b) {
   return  ((MAP*)a)->num - ((MAP*)b)->num;
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *res = (int *)malloc(2 * sizeof(int));
    res[0] = 0;
    res[1] = 0;
    *returnSize = 0;
    if (NULL == nums || numsSize < 2) return res;
    
    MAP *maps = (MAP *)malloc(numsSize * sizeof(MAP));
    for (int i = 0; i < numsSize; i++) {
        maps[i].num = nums[i];
        maps[i].index = i;
    }
    
    qsort(maps, numsSize, sizeof(MAP), cmpfunc);

    int i = 0;
    int j = numsSize - 1;
    
    while (i < j) {
        int front = maps[i].num;
        int back  = maps[j].num;
        if (front + back == target) {
            res[0]  = maps[i].index;
            res[1]  = maps[j].index;
            *returnSize = 2;
            break;
        } else if (front + back > target) {
            j--;
        } else if (front + back < target) {
            i++;
        }
    }
    
    free(maps);
    maps = NULL;
    
    
    return res;
}

 

 


 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luuyiran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值