leetcode——探索字节跳动系列题目

今天登陆leetcode发现探索区多了字节跳动的专栏,特意用了一下午去刷,有些是之前刷过的。但题目不错,就当是复习一遍吧,这里记录一下我会的以及自己觉得不错的题目。

原题链接请点击题目

一:挑战字符串

3. 无重复字符的最长子串

分析:这题要求连续的不重复的最长子序列的长度,注意这里是需要连续,利用这个特性,我们可以维护一个窗口,窗口装的是无重复的字符串,一开始窗口的左边在起点(即下标为0处)。我们用 i 遍历字符串,如果当前字符没有出现过或者当前字符虽然出现过但不在当前的窗口,则窗口向右扩张。而当当前字符出现在窗口内,则窗口的左边收缩到当前字符前一个出现的位置。详见代码

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //维护一个滑动窗口,最大的窗口大小即为结果
        int hash[128] = {0};
        int left = 0,res = 0;
        for(int i = 0;i<s.size();i++)
        {
            if(hash[s[i]] == 0||hash[s[i]]<left)  //1:没出现过 2:出现过但没在窗口内  
                res = max(res,i-left+1);      //不断更新res值
            else
                left = hash[s[i]];       //窗口内出现重复,缩小左边窗口
            hash[s[i]] = i+1;
        }
        return res;
    }
};

14. 最长公共前缀

简单题,以第一个字符串作为模版,逐个拿出模版的每个字符,然后其余的字符串也逐个拿出相对应位置的字符比较是否相同。注意字符串长度的问题即可。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.empty()) return "";
        string res = "";
        for(int i = 0;i<strs[0].size();i++)
        {
            char c = strs[0][i];          //逐个拿出模版字符串的字符
            for(int j = 1;j<strs.size();j++) //后面的字符串
            {
                if(i>=strs[j].size()||strs[j][i]!=c) //当i已经超过字符串的长度或者字符不相同时直接返回
                    return res;
            }
            res+=c;
        }
        return res;
    }
};

567. 字符串的排列

分析:对s2全排再一一跟s1对比肯定会超时。所以我们可以维护两个窗口,一个窗口装s1,另一个窗口装s2。假设s1长度为len1,s2长度为len2。开始先分别装s1和s2的前lne1个字符进各自的窗口。如果此时两个窗口相等则直接返回true,如果不等则s2的窗口从len1开始装s2的字符,同时窗口的左边要删除一个元素,因为两个窗口要保持大小,期间如果两个窗口相等则返回true

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        //v1、v2维护一个大小相同的窗口,先计算出len1前的字符出现的次数,如果相等直接返回TURE,如果不等则操作v2继续往后走,后面的字符添上,窗口左边的字符删除
        int len1 = s1.size(),len2 = s2.size();
        vector<int> v1(128,0),v2(128,0);
        for(int i = 0;i<len1;i++)
        {
            v1[s1[i]]++;
            v2[s2[i]]++;
        }
        if(v1==v2) return true;
        for(int i = len1;i<len2;i++)  //v2从len1位置开始装
        {
            v2[s2[i]]++;            //装新的字符
            v2[s2[i-len1]]--;       //删除早装入的字符
            if(v1 == v2)
                return true;
        }
        return false;
    }
};

43. 字符串相乘

分析:这里主要开了三个数组来做,一个数组存第一个字符串,另一个数组存第二个字符串,最后一个数组存结果。保存两个字符串的时候要反着顺序存,因为我们平时做乘法的时候也是从数字的最后一位向前乘的,所以其实这道题主要是模拟了平时在纸上做的乘法。

class Solution {
public:
    string multiply(string num1, string num2) {
        int x[120] = {0},y[120] = {0},z[250] = {0};
        int len1 = num1.size(),len2 = num2.size();
        for(int i = len1-1,k = 0;i>=0;i--)
            x[k++] = num1[i]-'0';
        for(int i = len2-1,k = 0;i>=0;i--)
            y[k++] = num2[i]-'0';
        for(int i = 0;i<len1;i++)    //在这里进行相乘,但没进位
        {
            for(int j = 0;j<len2;j++)
                z[i+j] += (x[i]*y[j]);
        }
        for(int i = 0;i<249;i++)   //现在进位
        {
            if(z[i]>9)
            {
                z[i+1] += z[i]/10;
                z[i]%=10;
            }
        }
        int i;
        for(i = 249;i>=0;i--)
            if(z[i] != 0)
                break;
        string res = "";
        for(;i>=0;i--)
            res+=(z[i]+'0');
        if(res == "") return "0";
        return res;
    }
};

 

151. 翻转字符串里的单词

分析:主要做法就是先把整个字符串反转,然后开始遍历字符串,每遍历完一个单词(注意不是一个字符)的时候将这个单词再反转。

class Solution {
public:
    void reverseWords(string &s) {
        int index = 0,n = s.size();
        reverse(s.begin(),s.end()); //反转整个字符串
        for(int i = 0;i<n;i++)
        {
            if(s[i]!=' ')     //遇到非空格的字符
            {
                if(index!=0)
                    s[index++] = ' ';
                int j = i;       //令j = i 进行下面的操作
                while(j<n&&s[j]!=' ')  //遍历完整一个单词
                    s[index++] = s[j++];
                reverse(s.begin()+index-(j-i),s.begin()+index); //对刚才遍历的单词进行反转
                i = j;
            }
        }
        s.resize(index);
    }
};

93. 复原IP地址

分析:一般题目问字符串有多少种可能的排列,十有八九都是用递归做的。我们需要先写一个函数判断一个字符串是否符合ip其中一个结点,符合的标准:1、1到3位长度的字符串。2、长度大于一的话首位不能为0。3、整数大小要在0~255的范围内。

接着就可以递归做正式工作。这里对字符串分别截取一位、二位、三位。。。判断是否能构成ip的一个结点,如果能的话就截断这部分,让剩余的部分递归下去继续做判断。

具体看代码

class Solution {
public:
    vector<string> restoreIpAddresses(string s) {
        vector<string> res;
       // string out = "";
        helper(res,s,"",4);
        return res;
    }
    
    void helper(vector<string>& res,string s,string out,int k)
    {
        if(k==0)
        {
            if(s.empty())     //注意点一,原字符串s应该要为空了
                res.push_back(out);
        }
        else
        {
            for(int i = 1;i<=3;i++)
            {
                //截取某部分进行判断,如果合法则进入下一个递归
                if(s.size()>=i&&isValid(s.substr(0,i)))  //注意点二,越界判断
                {
                    if(k==1)  //k==1代表当前ip再添加多一个结点就够四个了
                        helper(res,s.substr(i),out+s.substr(0,i),k-1);
                    else
                        helper(res,s.substr(i),out+s.substr(0,i)+'.',k-1);
                }
            }
        }
    }
    
    //判断是否合法
    bool isValid(string s)
    {
        if(s.empty()||s.size()>3||(s.size()>1&&s[0]=='0'))
            return false;
        int num = atoi(s.c_str());
        return num>=0&&num<=255;
    }
};

二、数组与排序

15. 三数之和

class Solution {
public:
    //做法类似双指针一头一尾向中间靠拢
    //需要注意的是题目给出的是三个数字,那么我们只需让目标数(也即是0)减去第一个数得到的结果当做
    //剩下两个数的目标和
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        sort(nums.begin(),nums.end());
        for(int i = 0;i<nums.size();i++)
        {
            if(nums[i]>0) break;
            if(i>0&&nums[i] == nums[i-1])
                continue;
            int target = 0-nums[i];
            int j = i+1,k = nums.size()-1;
            while(j<k)
            {
                if(nums[j]+nums[k] == target)
                {
                    res.push_back({nums[i],nums[j],nums[k]});
                    while(j<k&&nums[j+1] == nums[j]) j++;
                    while(j<k&&nums[k-1] == nums[k]) k--;
                    j++;k--;
                }
                else if(nums[j]+nums[k]<target)
                    j++;
                else
                    k--;
            }
        }
        return res;
    }
};

 

674. 最长连续递增序列

class Solution {
public:
    int findLengthOfLCIS(vector<int>& nums) {
        int res = 0,cnt = 0;
        int cur = INT_MAX;
        for(int num:nums)
        {
            if(num>cur)
                cnt++;
            else cnt = 1;
            res = max(res,cnt);
            cur = num;
        }
        return res;
    }
};

 

三、链表与树

2. 两数相加

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //两个链表一个一个结点拆分下来相加就,相加得到的结果加到一个新的链表的末尾,注意进位
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int add = 0;
        ListNode* res = new ListNode(0);
        ListNode* head = res;
        while(l1||l2||add)
        {
            int num = (l1?l1->val:0)+(l2?l2->val:0)+add;
            head->next = new ListNode(num%10);
            head = head->next;
            add = num/10;
            l1 = l1?l1->next:l1;
            l2 = l2?l2->next:l2;
        }
        return res->next;
    }
};

 

148. 排序链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    //对于单链表,归并排序是最简单的了。merge函数实现的功能是合并两个排序链表
    ListNode* sortList(ListNode* head) {
        if(!head||!head->next) return head;
        ListNode* slow = head,*fast = head,*pre = head;
        while(fast&&fast->next)
        {
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        pre->next = NULL;
        return merge(sortList(head),sortList(slow));
    }
    
    ListNode* merge(ListNode* a,ListNode* b)
    {
        ListNode* head = new ListNode(0);
        ListNode* node = head;
        while(a&&b)
        {
            if(a->val<b->val)
            {
                node->next = a;
                a = a->next;
            }
            else
            {
                node->next = b;
                b = b->next;
            }
            node = node->next;
        }
        if(a) node->next = a;
        if(b) node->next = b;
        return head->next;
    }
};

 

142. 环形链表 II

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* fast = head;
        ListNode* slow = head;
        while(fast&&fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            if(slow == fast)
                break;
        }
        if(!fast||!fast->next) return NULL;
        slow = head;
        while(fast != slow)
        {
            slow = slow->next;
            fast = fast->next;
        }
        return fast;
    }
};

 

236. 二叉树的最近公共祖先

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root||p==root||q==root) return root;
        TreeNode* left = lowestCommonAncestor(root->left,p,q);
        TreeNode* right = lowestCommonAncestor(root->right,p,q);
        if(left&&right)    //p和q分别位于左右子树中
            return root;
        return left?left:right;
    }
};

 

四、动态或贪心

121. 买卖股票的最佳时机

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0,buy = INT_MAX;
        for(auto c:prices)
        {
            buy = min(buy,c);
            res = max(res,c-buy);
        }
        return res;
    }
};

 

122. 买卖股票的最佳时机 II

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if(len<=1)
            return 0;
        vector<int> have(len);
        vector<int> unhave(len);
        have[0] = -prices[0];
        int res = 0;
        for(int i = 1;i<len;i++)
        {
            unhave[i] = max(unhave[i-1],have[i-1]+prices[i]);
            have[i] = max(have[i-1],unhave[i-1]-prices[i]);
            res = max(res,unhave[i]);
        }
        return res;
    }
};

 

221. 最大正方形

class Solution {
public:
    int maximalSquare(vector<vector<char>>& matrix) {
        if(matrix.empty()||matrix[0].empty()) return 0;
        int m = matrix.size(),n = matrix[0].size();
        vector<vector<int>> dp(m,vector<int>(n,0));
        int res = 0;
        for(int i = 0;i<m;i++)
        {
            for(int j = 0;j<n;j++)
            {
                if(i == 0||j == 0)
                    dp[i][j] = matrix[i][j]-'0';
                else if(matrix[i][j] == '1')
                    dp[i][j] = min(min(dp[i-1][j-1],dp[i-1][j]),dp[i][j-1])+1;
                res = max(res,dp[i][j]);
            }
        }
        return res*res;
    }
};

 

 

  • 1
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值