[日常刷题]leetcode D26

版权声明:希望各位多提意见多多互相交流哦~ https://blog.csdn.net/wait_for_taht_day5/article/details/82948141

268. Missing Number

Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one that is missing from the array.

Example 1:

Input: [3,0,1]
Output: 2

Example 2:

Input: [9,6,4,2,3,5,7,0,1]
Output: 8

Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?

Solution in C++:

关键点:

  • 数为0-n连续数列中丢失一个数

思路:

  • 这题因为原来有同学跟我提过,第一个想法就是求和公式,既快也省空间。
  • 然后看了下题解还有很多种方法,这里代码和解析就列举我觉得不错的方法。
  • 感觉就是异或操作这个方法不错,由于数列下标是从0开始的,所以在异或的操作中还要加入n,通过结果来判断谁只有一个。

方法一:数列求和公式

int missingNumber(vector<int>& nums) {
        size_t size = nums.size();
        int sum = size * (size + 1) / 2;
        int total = 0;
        for(auto num : nums)
            total += num;
        
        return sum - total;
    }

方法二:异或操作

int missingNumber(vector<int>& nums) {
        size_t size = nums.size();
        int missing = size;
        for(int i = 0; i < size; ++i)
            missing ^= i ^ nums[i];
        return missing;
    }

278. First Bad Version

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.

Suppose you have n versions [1, 2, ..., n]and you want to find out the first bad one, which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether versionis bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

Example:

Given n = 5, and version = 4 is the first bad version.

call isBadVersion(3) -> false
call isBadVersion(5) -> true
call isBadVersion(4) -> true

Then 4 is the first bad version. 

Solution in C++:

关键点:

  • int范围

思路:

  • 哇,最开始写了个二分查找,居然T了,然后看了解析居然第一个是暴力,我就想不通了,后来发现竟然是因为数据范围炸了,以后坚决只写left + (right - left) / 2 了。我这里的想法很简单,主体就是二分查找的思想,然后加一点点优化,如果找到坏版本后看看前面一个是否是好版本,是即找到了,不是继续。这里有个情况就是当找到第一个的时候就不能进行这个操作,不然会成为0,undefined。
// Forward declaration of isBadVersion API.
bool isBadVersion(int version);

class Solution {
public:
    int firstBadVersion(int n) {
        int left = 1;
        int right = n;
        int result = 0;
        
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if (isBadVersion(mid)) // 是坏的版本
            {
                if (mid == 1)
                    return mid;
                
                // 判断前一个是否为好的版本
                if (!isBadVersion(mid - 1))
                    return mid;
                else
                {
                    right = mid - 1;
                }
            } else{  // 不是坏的版本
                left = mid + 1;
            }
        }
        return left;
    }
};

283. Move Zeroes

Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.

Example:

Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

Note:

  1. You must do this in-place without making a copy of the array.
  2. Minimize the total number of operations.

Solution in C++:

关键点:

  • 保持原来非零元素顺序

思路:

  • 开始想着记录元素位置来移动元素,后来觉得太麻烦了,而且语言提供了便利的操作,我这里的主要思想是把零元素全部去掉,然后再在尾部添加零元素。其中需要注意的点:1.迭代器it的更新 2.数组长度的变化 3.连续0删除的方法 4.最后0的识别
  • 看了解析解决方案都差不多,这里就讲最优的,主要思想就是从头开始遍历数组,另外一个变量用于记录非零元素的下标(当前扫到的个数),将0与之交换位置。因为下标从0开始,所以扫到的在前面的非零元素一定也在前方,即相对位置不变。

方法一:vector erase

void moveZeroes(vector<int>& nums) {
        size_t size = nums.size();
        if ( size == 0)
            return;
        
        // 统计零元素的个数
        
        size_t zeroNums = 0;
        for(int i = 0; i < size; ++i){
            vector<int>::iterator it = nums.begin();
            
            while (nums[i] == 0){
                    nums.erase(it + i);
                    ++zeroNums;
                    --size;
                    it = nums.begin();
                    if (i == size)
                        break;
                }
        }
                
        for(int i = 0; i < zeroNums; ++i)
            nums.push_back(0);
    }

方法二:交换元素

void moveZeroes(vector<int>& nums) {
    for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
        if (nums[cur] != 0) {
            swap(nums[lastNonZeroFoundAt++], nums[cur]);
        }
    }
}

290. Word Pattern

Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

Example 1:

Input: pattern = "abba", str = "dog cat cat dog"
Output: true

Example 2:

Input:pattern = "abba", str = "dog cat cat fish"
Output: false

Example 3:

Input: pattern = "aaaa", str = "dog cat cat dog"
Output: false

Example 4:

Input: pattern = "abba", str = "dog dog dog dog"
Output: false

Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters separated by a single space.

Solution in C++:

关键点:

  • 双向映射

思路:

  • 这个之前好像在字母替换的时候做过类似的,大概思路都是差不多的,就是使用两个map来达到双向映射的效果。
  • 这里没有解析,但是在discuss中看到了不错的解答,一个是写法让我有收获,一个是在我的方法之上是有优化的。这里通过都映射到int的方式来达到双向映射的效果。

方法一: my solution

bool wordPattern(string pattern, string str) {

    // 特殊情况
    if (pattern.size() == 0 && str.size() == 0)
        return true;
    else if (pattern.size() == 0 || str.size() == 0)
        return false;

    // 正常情况
    map<char,string> maps;
    map<string,int> table;

    int i = 0;
    string tmp;
    int pos = 0;

    while(pos != -1){
        pos = str.find(" ");
        map<char,string>::iterator it = maps.find(pattern[i]);

        if (pos != -1)
            tmp = str.substr(0,pos);
        else
            tmp = str;
        map<string,int>::iterator its = table.find(tmp);

        if (it != maps.end()) // 模式字母已出现过
        {
            cout << maps[pattern[i]] << endl;
            if (tmp != maps[pattern[i]])
                return false;
        } else{               // 未出现过
            if (its != table.end())
                return false;
            else
                table[tmp] = 1;
            maps[pattern[i]] = tmp;
        }
        i++;
        str = str.substr(pos+1);
}

     return i == pattern.size();
}

方法二:optimal solution

bool wordPattern(string pattern, string str) {
    map<char, int> p2i;
    map<string, int> w2i;
    istringstream in(str);
    int i = 0, n = pattern.size();
    for (string word; in >> word; ++i) {  				// 字符串的遍历方式
        if (i == n || p2i[pattern[i]] != w2i[word])     // 如果一方不存在,则不等
            return false;
        p2i[pattern[i]] = w2i[word] = i + 1;
    }
    return i == n;
}

小结

今天学的还蛮多的,都是一些小的知识点。

知识点

  • XOR性质,自己是自己的相反
  • left + (right - left) / 2 防超过范围
  • 通过映射第三个达到双向映射效果; istringstream in(str); in >> word来循环

猜你喜欢

转载自blog.csdn.net/wait_for_taht_day5/article/details/82948141
今日推荐