刷不动的leetcode(七)1024节到100道啦

545 阅读14分钟

81.给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。

注意:

十六进制中所有字母(a-f)都必须是小写。
十六进制字符串中不能包含多余的前导零。如果要转化的数为0,那么以单个字符'0'来表示;对于其他情况,十六进制字符串中的第一个字符将不会是0字符。 
给定的数确保在32位有符号整数范围内。
不能使用任何由库提供的将数字直接转换或格式化为十六进制的方法。

示例 1:

输入: 26

输出: "1a"

示例 2:

输入: -1

输出: "ffffffff"

class Solution {
public:
    string toHex(int num) {
        if(!num)
            return "0";
        string res;
        int k=0;
        while(num&&res.size()<8)
        {   
            k=num&0xf;
            k+=k>9?'a'-10:'0';
            res=(char)k+res;
            num>>=4;
        }
        return res;
    }
};

82.给定一个包含大写字母和小写字母的字符串,找到通过这些字母构造成的最长的回文串。

在构造过程中,请注意区分大小写。比如 "Aa" 不能当做一个回文字符串。

注意: 假设字符串的长度不会超过 1010。

示例 1:

输入: "abccccdd"

输出: 7

解释: 我们可以构造的最长的回文串是"dccaccd", 它的长度是 7。

class Solution {
public:
    int longestPalindrome(string s) {
        int flag=0;
        int ask[60]={};
        int res=0;
        for(int i=0;i<s.size();i++)
            ask[s[i]-'A']++;
        for(int i=0;i<60;i++)
        {
            if(!flag&&ask[i]%2)
                flag=1;
            res+=ask[i]&(~0x1);
        }
        return res+flag;
    }
};

83.写一个程序,输出从 1 到 n 数字的字符串表示。

  1. 如果 n 是3的倍数,输出“Fizz”;
  2. 如果 n 是5的倍数,输出“Buzz”;

3.如果 n 同时是3和5的倍数,输出 “FizzBuzz”。

示例:

n = 15,

返回: [ "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz" ]

class Solution {
public:
    vector<string> fizzBuzz(int n) {
        vector<string> res;
        for(int i=1;i<=n;i++)
        {
            switch(i%15)
            {
                case 0:
                    res.push_back("FizzBuzz");
                    break;
                default:
                    if(i%3==0)	//注意此处的!号优先级高于%
                        res.push_back("Fizz");
                    else if(i%5==0)
                        res.push_back("Buzz");
                    else
                        res.push_back(to_string(i));
                    break;
            }
                
        }
        return res;
    }
};

84.给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。

示例 1:

输入: [3, 2, 1]

输出: 1

解释: 第三大的数是 1.

示例 2:

输入: [1, 2]

输出: 2

解释: 第三大的数不存在, 所以返回最大的数 2 .

示例 3:

输入: [2, 2, 3, 1]

输出: 1

解释: 注意,要求返回第三大的数,是指第三大且唯一出现的数。 存在两个值为2的数,它们都排第二。

//太烦了,借用的别人的代码,不想写!
class Solution {
public:
    int thirdMax(vector<int>& nums) {
        int n=nums.size();
        long long max1=LONG_MIN, max2=LONG_MIN, max3=LONG_MIN;
        for(int i=0;i<n;i++)
        {
            if(nums[i]>max1)
            {
                max3=max2;
                max2=max1;
                max1=nums[i];
            }
            else if(nums[i]<max1 && nums[i]>max2)
            {
                max3=max2;
                max2=nums[i];
            }
            else if(nums[i]<max2 && nums[i]>max3)
                max3=nums[i];
        }
        if(max3!=LONG_MIN)
            return max3;
        else
            return max1;
    }
};

85.给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。

注意:

num1 和num2 的长度都小于 5100.
num1 和num2 都只包含数字 0-9.
num1 和num2 都不包含任何前导零。
你不能使用任何內建 BigInteger 库, 也不能直接将输入的字符串转换为整数形式。
//自己写的太麻烦,一个大佬写的,感觉得吸收吸收人家的想法
class Solution {
public:
    string addStrings(string num1, string num2) {
        string str;
        int cur = 0, i = num1.size()-1, j = num2.size()-1;
        while (i >= 0 || j >= 0 || cur != 0) {
            if (i >= 0) cur+=num1[i--]-'0';
            if (j >= 0) cur+=num2[j--]-'0';
            str=to_string(cur%10)+str;
            cur/=10;
        }
        return str;
    }
};

86.给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。

/*
//注意是N叉树不是二叉树
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/
class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        if(!root)
            return {};
        queue<Node*> q;
        vector<vector<int>> res;
        vector<int> resl;
        q.push(root);
        Node* p=q.back();
        while(!q.empty())
        {
            Node* r=q.front();
            q.pop();
            resl.push_back(r->val);
            for(int i=0;i<r->children.size();i++)
                q.push(r->children[i]);
            if(r==p)
            {   
                p=q.back();
                res.push_back(resl);
                resl.clear();
            }
        }
        return res;
    }
};

87.统计字符串中的单词个数,这里的单词指的是连续的不是空格的字符。

请注意,你可以假定字符串里不包括任何不可打印的字符。

示例:

输入: "Hello, my name is John" 输出: 5

//按理来说是过了,出题人纯粹恶心我。。。。
class Solution {
public:
    int countSegments(string s) {
        int k=0;
        int res=0;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]>='A'&&s[i]<='z')
                k=1;
            else
            {
                res+=k;
                k=0;
            }
        }
        return res+k;
    }
};

88.给定一个二叉树,它的每个结点都存放着一个整数值。

找出路径和等于给定数值的路径总数。

路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。

示例:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

  10
 /  \
5   -3

/ \
3 2 11 / \
3 -2 1

返回 3。和等于 8 的路径有:

  1. 5 -> 3
  2. 5 -> 2 -> 1
  3. -3 -> 11
//只能做优化,理论上时间复杂度都差不多
class Solution {
public:
    // 方法2:使用vector存储下当前路径下遍历过的结点,每遍历到一个结点,就倒序遍历 vector,求出每个包含当前结点的符合要求的结果
    int pathSum(TreeNode* root, int sum){
        vector<int> path;
        int pathCount = 0;
        pathSumCore(root, sum, path, pathCount);
        return pathCount;
    }
    void pathSumCore(TreeNode* root, int sum, vector<int> &path, int &pathCount){
        if(root == nullptr) return;
        path.push_back(root->val);
        int currSum = 0;
        for(int i = path.size() - 1; i >= 0; i--){
            currSum = currSum + path[i];
            if(currSum == sum){
                pathCount++;
            }
        }
        pathSumCore(root->left, sum, path, pathCount);
        pathSumCore(root->right, sum, path, pathCount);
        path.pop_back();
    }
};

89.你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。

给定一个数字 n,找出可形成完整阶梯行的总行数。

n 是一个非负整数,并且在32位有符号整型的范围内。

class Solution {
public:
    int arrangeCoins(int n) {
        return sqrt((long)2*n+0.25)-0.5;
    }
};

90.给定一组字符,使用原地算法将其压缩。

压缩后的长度必须始终小于或等于原数组长度。

数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。

在完成原地修改输入数组后,返回数组的新长度。

进阶: 你能否仅使用O(1) 空间解决问题?

示例 1:

输入: ["a","a","b","b","c","c","c"]

输出: 返回6,输入数组的前6个字符应该是:["a","2","b","2","c","3"]

说明: "aa"被"a2"替代。"bb"被"b2"替代。"ccc"被"c3"替代。

示例 2:

输入: ["a"]

输出: 返回1,输入数组的前1个字符应该是:["a"]

说明: 没有任何字符串被替代。

示例 3:

输入: ["a","b","b","b","b","b","b","b","b","b","b","b","b"]

输出: 返回4,输入数组的前4个字符应该是:["a","b","1","2"]。

说明: 由于字符"a"不重复,所以不会被压缩。"bbbbbbbbbbbb"被“b12”替代。 注意每个数字在数组中都有它自己的位置。

class Solution {
public:
    int compress(vector<char>& chars) {
        int p=0;
        int k=chars[0];
        int k_num=0;
        chars.push_back(-1);//重要的是这个哨兵!
        for(int i=0,k_num=0;i<chars.size();i++,k_num++)
        {
             if(chars[i]!=k)
             {
                 chars[p++]=k;
                 if(k_num>1)
                 {string s=to_string(k_num);
                 for(int i=0;i<s.size();i++)
                     chars[p++]=s[i];}
                 k_num=0;
                 k=chars[i];
             }
        }
        return p;      
    }
};

91.给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。

找到所有在 [1, n] 范围之间没有出现在数组中的数字。

您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。

示例:

输入: [4,3,2,7,8,2,3,1]

输出: [5,6]

/*【笔记】将所有正数作为数组下标,置对应数组值为负值。那么,仍为正数的位置即为(未出现过)消失的数字。

举个例子:

    原始数组:[4,3,2,7,8,2,3,1]

    重置后为:[-4,-3,-2,-7,8,2,-3,-1]

结论:[8,2] 分别对应的index为[5,6](消失的数字)*/
class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        for (int i = 0; i < nums.size(); ++i)
        nums[abs(nums[i])-1] = -abs(nums[abs(nums[i])-1]);
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i){
            if (nums[i] > 0)
                res.push_back(i+1);
        }
        return res;
        }
};

92.给定一个长度为 n 的非空整数数组,找到让数组所有元素相等的最小移动次数。每次移动可以使 n - 1 个元素增加 1。

示例:

输入: [1,2,3]

输出: 3

解释: 只需要3次移动(注意每次移动会增加两个元素的值):

[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]

//n-1个+1就是某个最大的减去1,一直所有的减少到min
class Solution {
public:
    int minMoves(vector<int>& nums) {
        long res=0;
        int min=nums[0];
        for(int i=0;i<nums.size();res+=nums[i],i++)
            if(nums[i]<min)
                min=nums[i];
        return res-nums.size()*min;
    }
};

93.假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:

你可以假设胃口值为正。 一个小朋友最多只能拥有一块饼干。

示例 1:

输入: [1,2,3], [1,1]

输出: 1

解释: 你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。 虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。 所以你应该输出1。

示例 2:

输入: [1,2], [1,2,3]

输出: 2

解释: 你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。 你拥有的饼干数量和尺寸都足以让所有孩子满足。 所以你应该输出2.

//简单题。。。
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int j=0;
        for(int i=0;i<s.size()&&j<g.size();i++)
        {
            if(s[i]>=g[j])
                j++;
        }
        return j;
    }
};

94.给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

示例 1:

输入: "abab"

输出: True

解释: 可由子字符串 "ab" 重复两次构成。

示例 2:

输入: "aba"

输出: False

示例 3:

输入: "abcabcabcabc"

输出: True

解释: 可由子字符串 "abc" 重复四次构成。 (或者子字符串 "abcabc" 重复两次构成。)

//kmp算法
class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int n=s.length();
        vector<int> next(n+1);
        next[0]=-1;
        int j=0, k=-1;
        while(j<n)
        {
            if(k==-1 || s[k]==s[j])
            {
                k++;
                j++;
                next[j]=k;
            }
            else
                k=next[k];
        }
        return next[n] && n%(n-next[n])==0;
        
    }
};

95.两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。

给出两个整数 x 和 y,计算它们之间的汉明距离。

注意: 0 ≤ x, y < 231.

示例:

输入: x = 1, y = 4

输出: 2

解释: 1 (0 0 0 1) 4 (0 1 0 0) ↑ ↑

上面的箭头指出了对应二进制位不同的位置。

class Solution {
public:
    int hammingDistance(int x, int y) {
        int res=0;
        for(int i=0,rev=x^y;i<32;res+=(rev&1),i++,rev>>=1);
        return res;
    }
};

96.给定一个包含 0 和 1 的二维网格地图,其中 1 表示陆地 0 表示水域。

网格中的格子水平和垂直方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

示例 :

输入: [[0,1,0,0], [1,1,1,0], [0,1,0,0], [1,1,0,0]]

输出: 16

//自己的智障写法
class Solution {
public:
    int islandPerimeter(vector<vector<int>>& grid) {
        int res=0;
        for(int i=0;i<grid.size();i++)
            for(int j=0;j<grid[0].size();j++)
            {
                if(grid[i][j])
                {
                    if(i==0)
                        res++;
                    else
                        res+=!grid[i-1][j];
                    if(i==grid.size()-1)
                        res++;
                    else
                        res+=!grid[i+1][j];
                    if(j==0)
                        res++;
                    else
                        res+=!grid[i][j-1];
                    if(j==grid[0].size()-1)
                        res++;
                    else
                        res+=!grid[i][j+1];
                }
            }
            return res;
    }
};

97.给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。

注意:

给定的整数保证在32位带符号整数的范围内。
你可以假定二进制数不包含前导零位。

示例 1:

输入: 5 输出: 2 解释: 5的二进制表示为101(没有前导零位),其补数为010。所以你需要输出2。

示例 2:

输入: 1 输出: 0 解释: 1的二进制表示为1(没有前导零位),其补数为0。所以你需要输出0。

//注意运算符的优先级关系
class Solution {
public:
    int findComplement(int num) {
        int v=1;
        for(int s=num;s>>1;s>>=1,v=(v<<1)+1);
        return num^v;
    }
};

98.给定一个二进制数组, 计算其中最大连续1的个数。

示例 1:

输入: [1,1,0,1,1,1] 输出: 3 解释: 开头的两位和最后的三位都是连续1,所以最大连续1的个数是 3.

注意:

输入的数组只包含 0 和1。
输入数组的长度是正整数,且不超过 10,000。
class Solution {
public:
    int findMaxConsecutiveOnes(vector<int>& nums) {
        int t=0;
        int res=0;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i])
                t++;
            else
            {
                res=max(t,res);
                t=0;
            }
        }
        return max(t,res);
    }
};

99.给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。

nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。

示例 1:

输入: nums1 = [4,1,2], nums2 = [1,3,4,2]. 输出: [-1,3,-1] 解释: 对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。 对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。 对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。

示例 2:

输入: nums1 = [2,4], nums2 = [1,2,3,4]. 输出: [3,-1] 解释: 对于num1中的数字2,第二个数组中的下一个较大数字是3。 对于num1中的数字4,第二个数组中没有下一个更大的数字,因此输出 -1。

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        map<int,int> M;
        vector<int> res;
        for(int i=0;i<nums2.size();i++)
            M[nums2[i]]=i;
        for(int i=0;i<nums1.size();i++)
        {
            if(M[nums1[i]]>-1)
            {
                int k=-1;
                for(int j=M[nums1[i]];j<nums2.size();j++)
                {
                    if(nums2[j]>nums1[i])
                    {k=nums2[j]; break;}
                }
                res.push_back(k);
            }
        }
        return res;
    }
};

100.给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词。键盘如下图所示。

American keyboard

示例:

输入: ["Hello", "Alaska", "Dad", "Peace"] 输出: ["Alaska", "Dad"]

class Solution {
public:
    vector<string> findWords(vector<string>& words) {
        vector<string> ans;
        for (string &w : words) {
            uint8_t byte = 7;
            for (char ch : w) {
                byte &= ht[tolower(ch) - 'a'];
                if (!byte) {
                    break;
                }
            }
            if (byte) {
                ans.push_back(w);
            }
        }
        return ans;
    }

private:
    vector<uint8_t> ht = {2, 4, 4, 2, 1, 2, 2, 2, 1, 2,
        2, 2, 4, 4, 1, 1, 1, 1, 2, 1, 1, 4, 1, 4, 1, 4};
};