LeetCode腾讯精选练习task01

这篇博客介绍了LeetCode上的三个经典题目:两数相加、寻找两个正序数组的中位数和最长回文子串。博主分享了C++解题思路和代码实现,同时提到了指针的运用和中位数求解的二分法。此外,还提供了Python版本的参考代码链接。
摘要由CSDN通过智能技术生成

两数相加

题目链接 2.两数相加
ps:在上次的组队学习中做了这个题目,这次就当是回顾一下指针的基础用法吧,因未系统学过指针的用法,就当是再学习学习。更新了部分注释以及解题思路。

题目描述

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。

如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807

解题思路

(于2021.1.10添加)

本题算是一个很简单题目,主要是掌握指针的基础用法。两数相加跟数组模拟的高精度加法差不多,需要注意的是要进位。

程序代码

c++

(注释于2021.1.10添加)

class Solution{
public:
    ListNode *addTwoNumbers(ListNode *l1, ListNode *l2){
        int digit = 0;
        int carryDigit = 0;
        ListNode *res = new ListNode(0);%指针的建立
        ListNode *tmpRes = res;%再建立一个指针,用于后面的操作
        while (l1 || l2 || carryDigit) {
            int tmpSum = 0;
            if (l1) {tmpSum += l1->val;l1 = l1->next;}
            if (l2) {tmpSum += l2->val;l2 = l2->next;}
            %如果此时l1和l2所指位置非空,就继续做加法
            tmpSum += carryDigit;%处理进位情况
            digit = tmpSum % 10;
            carryDigit = tmpSum / 10;
            //自己的收获就是下面这几行代码吧。
            ListNode *newLocation = new ListNode(digit);
            tmpRes->next = newLocation;
            %将得到的结果加入到tmpres指针中来,并将下一个位置指向newlocation
            tmpRes = tmpRes->next;
        }
        tmpRes = res->next;
        %因一开始res指针指的是最开始的位置,一直没有改变,
        %所以在这里把tmpres的指针位置指向res->next,方便输出
        return tmpRes;
    }
};
python

ps:(于2021.1.10添加)因最近这段时间还有其他事情要弄,就不再自己写Python版本,下面是datawhale给出的Python参考代码。

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        result = ListNode(-1)
        l3 = result
        flag = 0
        while l1 is not None and l2 is not None:
            a = l1.val
            b = l2.val
            c = a + b + flag
            l3.next = ListNode(c % 10)
            flag = 1 if c >= 10 else 0
            l1 = l1.next
            l2 = l2.next
            l3 = l3.next

        while l1 is not None:
            a = l1.val + flag
            l3.next = ListNode(a % 10)
            flag = 1 if a >= 10 else 0
            l1 = l1.next
            l3 = l3.next

        while l2 is not None:
            b = l2.val + flag
            l3.next = ListNode(b % 10)
            flag = 1 if b >= 10 else 0
            l2 = l2.next
            l3 = l3.next

        if flag == 1:
            l3.next = ListNode(flag)

        return result.next

心得

这题不难,主要是学会了如何在链表中进行赋值操作。顺便转发一下这个博客,之前参考了这个博客。单链表的创建、赋值 C++示例

寻找两个正序数组的中位数

题目链接 4. 寻找两个正序数组的中位数

题目描述

给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000

示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000

提示:
nums1.length== m
nums2.length== n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

解题思路

看到 log,很明显,我们只有用到二分的方法才能达到。我们不妨用另一种思路,题目是求中位数,其实就是求第 k 小数的一种特殊情况,而求第 k 小数有一种算法。
由于数列是有序的,其实我们完全可以一半儿一半儿的排除。假设我们要找第 k 小数,我们可以每次循环排除掉 k/2 个数。(摘自参考博客)

自我思考:很多跟中位数有关的题目,应该都可以转变思维,当做是第K小或者第K大的数

程序代码

c++
class Solution {
public:
    double getKth(vector<int>& nums1,int begin1,int end1,vector<int>& nums2,int begin2,int end2,int K) {
        int len1=end1-begin1+1;
        int len2=end2-begin2+1;
        %分别读取两个
        if(len1>len2) return getKth(nums2,begin2,end2,nums1,begin1,end1,K);
        %这里表示交换一下顺序,尽可能使长度小的那个数组为数组1
        if(len1==0) return nums2[begin2+K-1];
        
        if(K==1) return min(nums1[begin1],nums2[begin2]);
        %由于采取递归,当K==1的时候,表明已经找到了,
        %于是返回当前两个数组begin位置的最小的数
        int i=begin1+min(len1,K/2)-1;
        int j=begin2+min(len2,K/2)-1;
        %i,j表示当前这一层递归两个数组中需要比较的数的位置
        if(nums1[i]>nums2[j]) 
            return getKth(nums1,begin1,end1,nums2,j+1,end2,K-(j-begin2+1));
        else return getKth(nums1,i+1,end1,nums2,begin2,end2,K-(i-begin1+1));
    }
    %如果nums1[i]>nums2[j],则说明nums2中的前j个数,
    %都是比中位数要小,可以直接跳过
    %反之则是说明nums1中的前i个数都比中位数要小
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int n=nums1.size();
        int m=nums2.size();
        int left=(n+m+1)/2;
        int right=(n+m+2)/2;
        %处理奇数个和偶数个的情况,一个加一,一个加二,
        return (getKth(nums1,0,n-1,nums2,0,m-1,left)+getKth(nums1,0,n-1,nums2,0,m-1,right))*0.5;
    %这里return使用了两次查找,为了处理偶数个和奇数个两种情况,
    %奇数个的会返回一样的,偶数个就会返回不一样的,然后取中间值
    }
};

参考博客:
作者:windliang
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/

最长回文子串

题目链接 LeetCode 5. 最长回文子串

题目描述

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。

示例 2:
输入: “cbbd”
输出: “bb”

解题思路

暴力枚举法:
先枚举子串的端点 i 和 j ,然后再判断i~j的子串是否是回文串,如果是的话并且比原答案要长,就更新答案。此算法的复杂度为

中心扩展法思路分析:对该字符串的每一个位置都枚举一次,并以当前位置 i 扩展开,如果符合回文串的规定,并且比答案要长,我们就更新答案。粗略计算的该算法理论复杂度为O(N*N),但实际上不用花这么多时间。

DP版思路分析:
第一种:将字符串翻转形成一个新的字符串,这时两个字符串的最长公共子串就是最长回文子串,因为如果翻转过后还是有一样的子串,就说明这个子串是个回文串。
第二种:

马拉车算法思路分析:

程序代码

c++

c++dp版

class Solution {
public:
    string longestPalindrome(string s){
        int maxx=0,end;int store[1005][1005];
	    memset(store,0,sizeof(store));
	    if(s=="") return "";
	    string result("");
	    int n=s.size();
	    string reverseS=s;
	    reverse(reverseS.begin(),reverseS.end());
	    for(int i=0;i<n;++i)
		    for(int j=0;j<n;++j) 
			    if(s[i]==reverseS[j]){//这里利用查找公共子串的dp算法
				    if(i==0||j==0) store[i][j]=1;
				    else store[i][j]=store[i-1][j-1]+1;
				    if(store[i][j]>maxx) {
					//利用第二个reverseS字符串是由第一个翻转形成的特点,prej其实就是s字符里面回文串的起点 
					    int prej = n-1-j;
					    int nowj = prej+store[i][j]-1;
					    if(nowj==i) {
					    	end=i;
					    	maxx=store[i][j];
					    }	
				    }
			    }
		    result = s.substr(end+1-maxx,maxx);
		    return result;
        }
};

c++ 中心扩展版

class Solution {
public:
    string longestPalindrome(string s){
        //判断空字符串的情况
        if (s == ""){return "";}
        string result("");
        int sSize = int(s.size()); //选择一个中心点,向两侧扩展
        for (int i = 0; i < sSize; i++) {
            string tmpStr = expandHelper(s, i, i);//奇数组情况
            string tmpStr2 = expandHelper(s, i, i + 1);//偶数组情况
            if (int(tmpStr.size()) > int(result.size()))
                result = tmpStr;
            if (int(tmpStr2.size()) > int(result.size()))
                result = tmpStr2;
        }
        return result;
    }
    string expandHelper(string &s, int left, int right) {
        int sSize = int(s.size());
        while (left >= 0 && right < sSize && s[left] == s[right]) {left--; right++;}
        return (s.substr(left + 1, right - left - 1));
    }
};

Python


参考博客:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/5-zui-chang-hui-wen-zi-chuan-cshi-xian-wu-chong-ji/
参考博客:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zhong-xin-kuo-san-dong-tai-gui-hua-by-liweiwei1419/(这一篇超详细)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值