两数相加
题目链接 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/(这一篇超详细)