Content
002 Add Two Numbers(M)
1.Problem Description
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
题意为将两个数字的每一位按逆序存储在非空链表中,要求求出两个数字之和,结果以同样的链表形式输出。
2.Analysis and Solution
思路比较简单,按照小学列竖式的加法规则按位计算。两个数字对应位数字之和加上上一轮的进位carry为sum,sum%10作为该位运算结果lastDigit存入结果链表,sum/10作为新的进位carry。若两个数字位数不相等,最后多出的部分按类似方法单独计算即可,同样需考虑进位。要注意最后一个进位的处理,不要遗漏。
因为这里使用结构体创建链表结构,需要熟悉单链表的访问方法,另外需要额外存储结果链接的头节点作为最后的输出。
3.Code
ListNode* addTwoNums(ListNode* l1, ListNode *l2)
{
ListNode* l3 = new ListNode(0);
ListNode* l3_head = new ListNode(0);
l3_head = l3;
int carry = 0, sum = 0, lastDigit = 0;
while(l1!= nullptr && l2!= nullptr)
{
sum = carry + l1->val + l2->val;
carry = sum / 10;
lastDigit = sum % 10;
l3->val = lastDigit;
l1 = l1->next;
l2 = l2->next;
if(l1!= nullptr && l2!= nullptr)
{
l3->next = new ListNode(0);
l3 = l3->next;
}
}
while(l1 != nullptr)
{
l3->next = new ListNode(0);
l3 = l3->next;
sum = carry + l1->val;
carry = sum / 10;
lastDigit = sum % 10;
l3->val = lastDigit;
l1 = l1->next;
}
while(l2 != nullptr)
{
l3->next = new ListNode(0);
l3 = l3->next;
sum = carry + l2->val;
carry = sum / 10;
lastDigit = sum % 10;
l3->val = lastDigit;
l2 = l2->next;
}
if(carry > 0)
{
l3->next = new ListNode(0);
l3 = l3->next;
l3->val = carry;
}
return l3_head;
}
004 Median of Two Sorted Arrays(H)
1.Problem Description
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.
Follow up: The overall run time complexity should be O(log (m+n)).
题意为输入两个有序数组,求出两个数组所有数字的中位数,同时确保时间复杂度为O(log (m+n))。
2.Analysis and Solution
这道题是刚刚结束学期算法期末考试的第一道题,没想到原来是leetcode上的hard题目。当时虽知道是用二分法,但苦思冥想好久也疏理不出解法。现在也是看了网上的一些解法才稍微明白了一些。
讨论里的解法也比较多,以官方题解为例。中位数即其恰好大于小于的元素,也大于一半的元素。设两个数组A、B长度分别为m,n,将两个数组进行分割,以较小的数组为准,不妨设m<n。若数组A在m1处划分,为使A[m1]大于一半的元素,则B的划分点n1满足m1+n1=(m+n+1)/2,m1的位置通过二分法寻找。具体涉及很多细节和边界问题的讨论,也是本题目的难点,这里自己也还没搞得特别清楚,就不班门弄斧了,可以参考leetcode给出的讨论。
3.Code
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if(nums2.length < nums1.length){
return findMedianSortedArrays(nums2,nums1);
}
int l1 = 0, r1 = nums1.length;
int lMax = 0, rMin = 0;
while(l1 <= r1){
int i = l1 + (r1 - l1)/2;
int j = (nums1.length + nums2.length + 1)/2 - i;
int nums1_i_1 = i == 0 ? Integer.MIN_VALUE : nums1[i-1];
int nums1_i = i == nums1.length ? Integer.MAX_VALUE : nums1[i];
int nums2_j_1 = j == 0 ? Integer.MIN_VALUE : nums2[j-1];
int nums2_j = j == nums2.length ? Integer.MAX_VALUE : nums2[j];
if(nums1_i_1 <= nums2_j){
lMax = Integer.max(nums1_i_1,nums2_j_1);
rMin = Integer.min(nums1_i,nums2_j);
l1 = i + 1;
}else{
r1 = i - 1;
}
}
return (nums1.length + nums2.length)%2 == 1 ? lMax : (lMax+rMin)/2.0;
}
}
005 Longest Palindromic Substring(M)
1.Problem Description
Given a string s, return the longest palindromic substring in s.
题意为给出一个字符串,找出其中最长的回文子串。回文串的含义就是从左向右遍历和从右向左遍历结果相同。
2.Analysis and Solution
这道题算是比较经典的题目,可以用动态规划求解。
子问题dp[i][j]表示字符串s从第i个到第j个字符构成的子串是否为回文串。
状态转移方程为:
d
p
[
i
]
[
j
]
=
d
p
[
i
+
1
]
[
j
−
1
]
&
&
(
s
[
i
]
=
=
s
[
j
]
)
dp[i][j]=dp[i+1][j-1] \&\&(s[i]==s[j])
dp[i][j]=dp[i+1][j−1]&&(s[i]==s[j])
初始状态为:
(1)
i
=
=
j
i==j
i==j时,仅有一个字符,显然是回文串,故
d
p
[
i
]
[
j
]
=
t
r
u
e
dp[i][j]=true
dp[i][j]=true;
(2)
i
=
=
j
−
1
i==j-1
i==j−1时,有两个字符,若它们相同,则为回文串,否则不是,因此
d
p
[
i
]
[
j
]
=
(
s
[
i
]
=
=
s
[
j
]
)
dp[i][j]=(s[i]==s[j])
dp[i][j]=(s[i]==s[j])
需要注意这里dp表的遍历方向,从初始状态向右上方遍历,每次找到回文串若比当前最长回文串长,则更新最长回文串,直到dp表遍历完成。
3.Code
string longsetPalindrome(string s)
{
int len = s.length();
bool p[len][len];
memset(p, 0, sizeof(p));
string ans;
for(int i = len - 1; i >= 0; i--)
{
for(int j = i; j < len; j++)
{
if(i == j)
p[i][j] = true;
else if(j == i + 1)
p[i][j] = (s[i] == s[j]);
else
p[i][j] = (p[i+1][j-1] && (s[i] == s[j]));
if(p[i][j] && (j - i + 1 > ans.length()))
ans = s.substr(i, j - i + 1);
}
}
return ans;
}