leetcode解题思路分析(四十六)395 - 401 题

  1. 至少有K个重复字符的最长子串
    找到给定字符串(由小写字符组成)中的最长子串 T , 要求 T 中的每一字符出现次数都不少于 k 。输出 T 的长度。

首先用哈希表算出每个字符出现个数,出现个数少于K的则作为分治的分割点,然后分割后长度小于当前最大子串长的则不需要计算了,直接剔除

class Solution {
    
    
public:
    int longestSubstring(string s, int k) 
    {
    
    
        unordered_map<char, int> umap;
        for (auto c : s) umap[c]++;
        vector<int> split;
        for (int i = 0; i < s.size(); i++) 
        {
    
    
            if (umap[s[i]] < k) split.push_back(i);
        }
        if (split.size() == 0) return s.length();
        int ans = 0, left= 0;
        split.push_back(s.length());
        for (int i = 0; i < split.size(); i++) 
        {
    
    
            int len = split[i] - left;
            if (len > ans) ans = max(ans, longestSubstring(s.substr(left, len), k));
            left = split[i]+1;
        }
        return ans;
    }
};

  1. 旋转函数
    给定一个长度为 n 的整数数组 A 。假设 Bk 是数组 A 顺时针旋转 k 个位置后的数组,我们定义 A 的“旋转函数” F 为:
    F(k) = 0 * Bk[0] + 1 * Bk[1] + … + (n-1) * Bk[n-1]。
    计算F(0), F(1), …, F(n-1)中的最大值。

数学计算题,数列求规律即可

class Solution {
    
    
public:
    int maxRotateFunction(vector<int>& A) {
    
    
        long N = A.size();
        long S = 0;
        long t = 0;
        for (int i = 0; i < N; ++i) {
    
    
            S += A[i];
            t += i * A[i];
        }
        long res = t;
        for (int i = N - 1; i >= 0; --i) {
    
    
            // F(k+1) = F(k) + S - n * Bk[n-1]
            t += S - N * (long)A[i];
            res = max(res, t);
        }
        return res;
    }
};


  1. 整数替换
    给定一个正整数 n,你可以做如下操作:1. 如果 n 是偶数,则用 n / 2替换 n。2. 如果 n 是奇数,则可以用 n + 1或n - 1替换 n。n 变为 1 所需的最小替换次数是多少?

本题的思路是采取位操作,然后针对奇数,希望尽可能多的一次性消除多位1,以此为判断依据来选择加1还是减1.注意3是特殊情况,需要排除

class Solution {
    
    
public:
    int integerReplacement(int n) {
    
    
        if (n == INT_MAX) // 处理溢出,也可以直接用long tmp = n;
            return 32;
        int count = 0;
        while (n != 1) 
        {
    
    
            if ((n & 1) == 0) 
            {
    
     // 偶数直接右移
                n >>= 1;
            } 
            else 
            {
    
    
                // 奇数 01减一, 11加1,特殊情况n = 3也是减1
                n += ((n & 2) == 0 || n == 3)? -1:1;
            }
            count++;
        }
        return count;
    }
};

  1. 随机数索引
    给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。

蓄水池采样法

class Solution {
    
    
public:
    vector<int>& nums;
    Solution(vector<int>& nums): nums(nums) {
    
    
    }
    
    int pick(int target) {
    
    
        int idx = -1, cnt = 0;
        for (int i = 0; i < nums.size(); ++i) {
    
    
            if (nums[i] == target && rand() % (++cnt) == 0) 
                idx = i;
        }
        return idx;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(nums);
 * int param_1 = obj->pick(target);
 */


  1. 除法求值
    给出方程式 A / B = k, 其中 A 和 B 均为用字符串表示的变量, k 是一个浮点型数字。根据已知方程式求解问题,并返回计算结果。如果结果不存在,则返回 -1.0。
    输入总是有效的。你可以假设除法运算中不会出现除数为 0 的情况,且不存在任何矛盾的结果。

把除法视为边,则该过程实际是一个邻接矩阵,如果存在边和边的逆,则返回,否则则为-1

class Solution {
    
    
public:
    vector<vector<double>> g;
    unordered_map<string, int> h;
    int n = 0;

    void floyd() {
    
    
        for(int k = 0; k < n; k++)
            for(int i = 0; i < n; i++)
                for(int j = 0; j < n; j++)
                    // 只有当g[i][k], g[k][j]能走的时候才进行更新 g[i][j]
                    if(g[i][k] >= 0 && g[k][j] >= 0) g[i][j] = g[i][k] * g[k][j];
    }

    vector<double> calcEquation(vector<vector<string>>& equations, vector<double>& values, vector<vector<string>>& queries) {
    
    
        // 将字符串映射到数组下标
        for(int i = 0; i < equations.size(); i++) {
    
    
            string a = equations[i][0], b = equations[i][1];
            if(!h.count(a)) h[a] = n++;
            if(!h.count(b)) h[b] = n++;
        }
        // 初始化邻接矩阵
        g = vector<vector<double>>(n ,vector<double>(n, -1)); // g[i][j] = -1 表示不能从 i 到 j
        for(int i = 0; i < n; i++)
            g[i][i] = 1; // 对角线初始化为 1 因为 a/a = 1
        for(int i = 0; i < equations.size(); i++) {
    
    
            // 添加边(双向)
            string a = equations[i][0], b = equations[i][1];
            g[h[a]][h[b]] = values[i];
            g[h[b]][h[a]] = 1 / values[i];
        }
        vector<double> res;
        floyd(); 
        for(auto q : queries) {
    
    
            string a = q[0], b = q[1]; 
            // 如果节点不存在或者a、b不联通则输出 -1
            if(!h.count(a) || !h.count(b) || g[h[a]][h[b]] == -1) res.push_back(-1.0);
            else {
    
    
                res.push_back(g[h[a]][h[b]]);
            }
        }
        return res;
    }
};


  1. 第N个数字
    在无限的整数序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, …中找到第 n 个数字。

理解了题意就很简单

class Solution {
    
    
public:
    int findNthDigit(int n) {
    
    
        // bit记录所在区间的位数,p记录所在区间的长度
        long long bit = 1, p = 9;
        while(n - bit * p > 0){
    
    
            n -= p * bit;
            bit++;
            p *= 10;
        }

        // num是答案所在数字
        int num = pow(10, bit - 1) + (n-1) / bit;

        // pos是答案在num中的位数(从左向右数)
        int pos = n % bit;
        pos = pos == 0 ? bit : pos;

        int t = pow(10, bit - pos);
        return num / t % 10;
    }
};


  1. 二进制手表
    给定一个非负整数 n 代表当前 LED 亮着的数量,返回所有可能的时间。

简单回溯法

class Solution {
    
    
public:
vector<string>res;
    unordered_map<int,int> hash={
    
    {
    
    0,1},{
    
    1,2},{
    
    2,4},{
    
    3,8},{
    
    4,1},{
    
    5,2},{
    
    6,4},{
    
    7,8},{
    
    8,16},{
    
    9,32}};
    void backtrack(int num,int start,pair<int,int>& time)
    {
    
    
        if(num==0)
        {
    
    
            if(time.first>11||time.second>59)//判断合法性
                return;
            string temp_hour=to_string(time.first);
            string temp_minute=to_string(time.second);
            if(temp_minute.size()==1)//如果minute只有一位要补0
                temp_minute.insert(0,"0");
            res.push_back(temp_hour+":"+temp_minute);//构造格式
            return;
        }
    
        for(int i=start;i<10;i++)
        {
    
    
            if(time.first>11||time.second>59)
                continue;
            pair<int,int>store=time;//保存状态
            if(i<4)
                time.first+=hash[i];
            else
                time.second+=hash[i];
            backtrack(num-1,i+1,time);//进入下一层,注意下一层的start是i+1,即从当前灯的下一盏开始
            time=store;//恢复状态
        }
    }
    vector<string> readBinaryWatch(int num) {
    
    
        pair<int,int>time(0,0);//初始化时间为0:00
        backtrack(num,0,time);
        return res;
    }

};

猜你喜欢

转载自blog.csdn.net/u013354486/article/details/109126131