2021.10.29 335. 路径交叉

 题目描述

给你一个整数数组 distance 。

从 X-Y 平面上的点 (0,0) 开始,先向北移动 distance[0] 米,然后向西移动 distance[1] 米,向南移动 distance[2] 米,向东移动 distance[3] 米,持续移动。也就是说,每次移动后你的方位会发生逆时针变化。

判断你所经过的路径是否相交。如果相交,返回 true ;否则,返回 false 。

思路

枚举可能产生相交的几种情况

1.d[i] 与 d[i - 3]d[i−3] 发生相交:此时满足 d[i] >= d[i - 2]d[i]>=d[i−2],同时 d[i - 1] <= d[i - 3]d[i−1]<=d[i−3];

LeetCode每日一题10.29-11.9_leetcode

2.d[i] 与 d[i - 4]d[i−4] 发生相交:此时满足 d[i - 1] = d[i - 3]d[i−1]=d[i−3],同时 d[i] + d[i - 4] >= d[i - 2]d[i]+d[i−4]>=d[i−2];

LeetCode每日一题10.29-11.9_算法_02

3.d[i]d[i] 与 d[i - 5]d[i−5] 发生相交:此时满足d[i - 1] <= d[i - 3]d[i−1]<=d[i−3],同时 d[i - 2] > d[i - 4]d[i−2]>d[i−4],同时 d[i] + d[i - 4] >= d[i - 2]d[i]+d[i−4]>=d[i−2],同时 d[i - 1] + d[i - 5] >= d[i - 3]d[i−1]+d[i−5]>=d[i−3]。

LeetCode每日一题10.29-11.9_刷题_03

代码

class Solution {
public:
    bool isSelfCrossing(vector<int>& distance) {
        int n = distance.size();
        if(n <= 3) return false;
        for(int i = 3; i < n; i++) {
            if(distance[i] >= distance[i-2] && distance[i-1] <= distance[i-3]) return true;
            if (i >= 4 && distance[i - 1] == distance[i - 3] && distance[i] + 
distance[i - 4] >= distance[i - 2]) return true;
            if (i >= 5 && distance[i - 1] <= distance[i - 3] && distance[i - 2] >
 distance[i - 4] && distance[i] + distance[i - 4] >= distance[i - 2] && 
distance[i - 1] + distance[i - 5] >= distance[i - 3]) return true;
        }
        return false;
    }
};
2021.10.30 260. 只出现一次的数字 III

题目描述

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

先看一个简单的题

136.只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?(异或

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (auto e: nums) ret ^= e;
        return ret;
    }
};

思路

哈希表、排序等等都不符合线性时间复杂度+空间复杂度O(1)

使用异或

利用除答案以外的元素均出现两次,我们可以先对 numsnums 中的所有元素执行异或操作,得到 sumsum,sumsum 为两答案的异或值(sumsum 必然不为 00)。

然后取 sumsum 二进制表示中为 1 的任意一位 k,sumsum 中的第 k 位为 1 意味着两答案的第 k 位二进制表示不同。

对 numsnums 进行遍历,对第 k 位分别为 0和 1的元素分别求异或和(两答案必然会被分到不同的组),即为答案。

LeetCode每日一题10.29-11.9_leetcode_04

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int xorsum = 0;
        for (int num: nums) {
            xorsum ^= num;
        }
        // 防止溢出
        int lsb = (xorsum == INT_MIN ? xorsum : xorsum & (-xorsum));
        int type1 = 0, type2 = 0;
        for (int num: nums) {
            if (num & lsb) {
                type1 ^= num;
            }
            else {
                type2 ^= num;
            }
        }
        return {type1, type2};
    }
};
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int xorsum = 0;
        for(int x:nums){
            xorsum ^= x;
        }
        int k = -1;
        for(int i = 31; i >= 0 && k == -1; i--) {
            if(((xorsum>>i) & 1) == 1) k = i;
        }
        int type1 = 0, type2 = 0;
        for(int x:nums){
            if(((x>>k) & 1) == 1) {
                type1 ^= x;
            }else {
                type2 ^= x;
            }
        }
        return {type1,type2};
    }
};
2021.10.31 500. 键盘行

题目描述

LeetCode每日一题10.29-11.9_i++_05

思路

哈希法:每行的字母保存在哈希表中,看每个单词是否都是同一个哈希表

或者直接给字母编号,不同的编号代表不同的行数。

class Solution {
public:
    vector<string> findWords(vector<string>& words) {
        vector<string> ans;
        string rowIdx = "12210111011122000010020202";
        for (auto & word : words) {
            bool isValid = true;
            char idx = rowIdx[tolower(word[0]) - 'a'];
            for (int i = 1; i < word.size(); ++i) {
                if(rowIdx[tolower(word[i]) - 'a'] != idx) {
                    isValid = false;
                    break;
                }
            }
            if (isValid) {
                ans.emplace_back(word);
            }
        }
        return ans;
    }
};
2021.11.1 575.分糖果

LeetCode每日一题10.29-11.9_算法_06

class Solution {
public:
    int distributeCandies(vector<int>& candyType) {
        set<int> types;
        int length = candyType.size() / 2;
        for(int x: candyType) {
            types.insert(x);
        }
        return length > types.size() ? types.size() : length;
    }
};
2021.11.2 237.删除链表中的节点

请编写一个函数,用于 删除单链表中某个特定节点 。在设计函数时需要注意,你无法访问链表的头节点 head ,只能直接访问 要被删除的节点 。

题目数据保证需要删除的节点 不是末尾节点 。

代码

class Solution {
public:
    void deleteNode(ListNode* node) {
        node->val = node->next->val;
        node->next = node->next->next;
    }
};
2021.11.3 407接雨水II

给你一个 m x n 的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。

LeetCode每日一题10.29-11.9_数组_07

 思路

和42.接雨水类似,只是从一维变到了二维。

设方块接水后的高度为water[i][j],则有:

LeetCode每日一题10.29-11.9_i++_08

矩阵的最外层的方块接水后的高度就是方块的自身高度,因为最外层的方块无法接水.

根据木桶原理,接到的雨水的高度由这个容器周围最短的木板来确定的。我们可以知道容器内水的高度取决于最外层高度最低的方块

我们假设已经知道最外层的方块接水后的高度的最小值,则此时我们根据木桶原理,肯定可以确定最小高度方块的相邻方块的接水高度。我们同时更新最外层的方块标记,我们在新的最外层的方块再次找到接水后的高度的最小值,同时确定与其相邻的方块的接水高度,

然后再次更新最外层,依次迭代直到求出所有的方块的接水高度,即可知道矩阵中的接水容量。

typedef pair<int,int> pii;

class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {  
        if (heightMap.size() <= 2 || heightMap[0].size() <= 2) {
            return 0;
        }  
        int m = heightMap.size();
        int n = heightMap[0].size();
        priority_queue<pii, vector<pii>, greater<pii>> pq;
        vector<vector<bool>> visit(m, vector<bool>(n, false));
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i == 0 || i == m - 1 || j == 0 || j == n - 1) {
                    pq.push({heightMap[i][j], i * n + j});
                    visit[i][j] = true;
                }
            }
        }

        int res = 0;
        int dirs[] = {-1, 0, 1, 0, -1};
        while (!pq.empty()) {
            pii curr = pq.top();
            pq.pop();            
            for (int k = 0; k < 4; ++k) {
                int nx = curr.second / n + dirs[k];
                int ny = curr.second % n + dirs[k + 1];
                if( nx >= 0 && nx < m && ny >= 0 && ny < n && !visit[nx][ny]) {
                    if (heightMap[nx][ny] < curr.first) {
                        res += curr.first - heightMap[nx][ny]; 
                    }
                    visit[nx][ny] = true;
                    pq.push({max(heightMap[nx][ny], curr.first), nx * n + ny});
                }
            }
        }
        
        return res;
    }
};
2021.11.4 367. 有效的完全平方数

思路

唯一需要注意的是:不适用库函数,遍历寻找完全平方数的时候需要放置溢出,得使用long数据类型。

class Solution {
public:
    bool isPerfectSquare(int num) {
        int x = (int) sqrt(num);
        return x * x == num;
    }
};
class Solution {
public:
    bool isPerfectSquare(int num) {
        long x = 1, square = 1;
        while (square <= num) {
            if (square == num) {
                return true;
            }
            ++x;
            square = x * x;
        }
        return false;
    }
};
class Solution {
public:
    bool isPerfectSquare(int num) {
        int left = 0, right = num;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            long square = (long) mid * mid;
            if (square < num) {
                left = mid + 1;
            } else if (square > num) {
                right = mid - 1;
            } else {
                return true;
            }
        }
        return false;
    }
};
2021.11.5 1218.最长定差子序列

LeetCode每日一题10.29-11.9_i++_09

很简单的动态规划,如果写两重循环会超时。关键点是第二趟循环可以不需要,当考虑序列中第i个元素时,需要找到0-i之间是否存在j满足arr[j] = arr[i] - difference。所以可以使用哈希表存起来。

class Solution {
public:
    int longestSubsequence(vector<int> &arr, int difference) {
        int ans = 0;
        unordered_map<int, int> dp;
        for (int v: arr) {
            dp[v] = dp[v - difference] + 1;
            ans = max(ans, dp[v]);
        }
        return ans;
    }
};

观察题目给定的数据范围为 -10^4到 10^4,且 d 的范围也是如此,为了防止越界,所以,我们声明一个4∗10^4的数组来记录以某个数结尾的长度。这样就可以不用map,提高效率。防止数组越界,需要理解v+20000的意思。

class Solution {
public:
    int longestSubsequence(vector<int> &arr, int difference) {
        int ans = 0;
        vector<int> dp(40001,0);
        for (int v: arr) {
            dp[v + 20000] = dp[v + 20000 - difference] + 1;
            ans = max(ans, dp[v + 20000]);
        }
        return ans;
    }
};


2021.11.6 268.丢失的数字

LeetCode每日一题10.29-11.9_leetcode_10

思路

思路1 排序

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            if (nums[i] != i) {
                return i;
            }
        }
        return n;
    }
};

思路2 哈希

思路3 异或

数组nums 中有n个数,在这n个数的后面添加从0到n的每个整数,则添加了n+1个整数,共有 2n+1整数。缺失的数字只出现了一次,对这2n+1个数异或,得到的结果即为缺失的数字。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int res = 0;
        int n = nums.size();
        for (int i = 0; i < n; i++) {
            res ^= nums[i];
        }
        for (int i = 0; i <= n; i++) {
            res ^= i;
        }
        return res;
    }
};

思路4:所有的下标和相加减去出现的数字即为缺失的数字。

思路5 

遍历一轮,对于出现的数字i,则将nums[abs(i)] 记为-1*nums[[abs(i)]]。再遍历一轮下来,数字为正的下标则是缺失的数字。

注意细节:

  • 对于某个下标i,若其值为n,则跳过。
  • 对于某个下标i,若其值为0,将nums[i] 记为-1*n,同时将nums[0] 记为-1*abs(num[0])。
class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0; i < n; i++) {
            int value = abs(nums[i]);//下标
            if(value == n) continue;
            if(nums[value] == 0) {
                nums[value] = -1 * n;
                nums[0] = -1 * abs(nums[0]);
                continue;
            }
            nums[value] = -1 * nums[value];
        }
        for(int i = 0; i < n; i++) {
            if(nums[i] >= 0 ) {
                return i;
            }

        }
        return n;
    }
};
2021.11.7 598.范围求和

LeetCode每日一题10.29-11.9_i++_11

思路

贼简单

class Solution {
public:
    int maxCount(int m, int n, vector<vector<int>>& ops) {
        int hang = m+1, lie = n+1;
        if(ops.size() == 0) return m * n;
        for(int i = 0; i < ops.size(); i++) {
            for(int j = 0; j < 2; j++) {
                hang = min(hang,ops[i][0]);
                lie = min(lie,ops[i][1]);
            }
        }
        return hang * lie;
    }
};
2021.11.8 299.猜数字游戏

LeetCode每日一题10.29-11.9_数组_12

 思路

LeetCode每日一题10.29-11.9_i++_13

代码

class Solution {
public:
    string getHint(string secret, string guess) {
        int length = secret.size();
        int a_sum = 0;
        int b_sum = 0;
        vector<int> sta1(10,0);
        vector<int> sta2(10,0);
        for(int i = 0; i < length; i++) {
            int x1 = secret[i] -'0';
            int x2 = guess[i] -'0';
            if(x1 == x2) {
                a_sum += 1;
                continue;
            }
            sta1[x1] += 1;
            sta2[x2] += 1;
        }
        for(int i = 0; i < 10; i++) {
            b_sum += min(sta1[i],sta2[i]);
        }
        return to_string(a_sum) + "A"+to_string(b_sum) + "B";
    }
};