LeetCode第2题: 两数相加
算法思路:
- 由于链表是从低位到高位, 我们可以逐位相加, 某一位为(l1.val + l2.val) % 10
- 由于存在进位问题, 需要设置一个变量作为进位, 其值为(l1.val + l2.val) // 10
- 如果在中途某个链表到头了, 那么就可以推出第一层循环, 循环单独的链表即可(这里可以使用将None补零, 来简化代码, 但是算法的复杂度并未简化)
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
c = 0
#这里新创建一个链表作为结果, head为其头结点
head = ListNode()
mid = head
# 第一层循环
while l1 is not None and l2 is not None:
p = ListNode()
p.val = (l1.val + l2.val + c) % 10
c = int((l1.val + l2.val + c) / 10)
mid.next = p
mid = mid.next
l1 = l1.next
l2 = l2.next
#第二层循环
while l1 is not None:
p = ListNode()
p.val = (l1.val + c) % 10
c = int((l1.val + c) / 10)
mid.next = p
mid = mid.next
l1 = l1.next
while l2 is not None:
p = ListNode()
p.val = (l2.val + c) % 10
c = int((l2.val + c) / 10)
mid.next = p
mid = mid.next
l2 = l2.next
#防止出现高位进位
if c == 1:
p = ListNode(1)
mid.next = p
return head.next
复杂度: 设链表长度分布为m, n, 由于该算法遍历了两个链表这复杂度为O(m+n)
LeetCode第四题: 寻找两个有序数组的中位数C语言实现
解法一
- 先找到两个数组的长度, 然后遍历找到中位数即可
- 如果是奇数个, 那么就直接返回, 如果是偶数个, 那么就返回它与它前一个树的和的平均数
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int target = (nums1Size + nums2Size) >> 1;
int i, j, pre, res;// pre记录res前边的一个数, res为返回结果
i = j = pre = res = 0;
// 判读跳出循环是因为一个数组到尽头了还是找到中位数了
int flag = 0;
// 计数器, 找到中位数
int count = -1;
while (i < nums1Size && j < nums2Size) {
pre = res;
res = nums1[i] < nums2[j] ? nums1[i++] : nums2[j++];
count++;
if (count == target) {
flag = 1;
break;
}
}
if (!flag) {
while (count != target) {
pre = res;
res = (i == nums1Size) ? nums2[j++] : nums1[i++];
count++;
}
}
return (nums1Size + nums2Size) & 1 ? res * 1.0 : (pre + res) * 1.0 / 2;
}
复杂度分析: 假设两个数组长度分别为m, n, 本算法的遍历次数为(n + m) / 2, 所以复杂度为O(m + n)
解法二
算法思想:
- 使用二分思想
- 本题相当于在两个有序数组中查找中位数, 可以使用二分方法依次排除不可能的取值
- 假设查找值为k, 那么A[0-k/2]和B[0-k/2]绝对不会是结果, 我们可以利用这个性质, 递归求得结果
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int k, flag = 0;
flag = (nums1Size + nums2Size) & 1;
if (!nums1Size) return flag ? nums2[(nums2Size >> 1)] : (nums2[(nums2Size) >> 1] + nums2[((nums2Size) >> 1) - 1]) * 1.0 / 2;
if (!nums2Size) return flag ? nums1[(nums1Size >> 1)] : (nums1[(nums1Size) >> 1] + nums1[((nums1Size) >> 1) - 1]) * 1.0 / 2;
k = flag ? ((nums1Size + nums2Size) >> 1) + 1 : ((nums1Size + nums2Size) >> 1);
int a1 = 0, a2 = 0;
while (k > 1) {
int offset = (k >> 1) - 1;
offset = a1 + offset >= nums1Size ? nums1Size - a1 - 1 : offset;
offset = a2 + offset >= nums2Size ? nums2Size - a2 - 1 : offset;
a1 += offset;
a2 += offset;
if (nums1[a1] <= nums2[a2]) {
a1 += 1;
a2 -= offset;
} else {
a1 -= offset;
a2 += 1;
}
k = k - (offset + 1);
if (a1 >= nums1Size) return flag ? nums2[a2 + k - 1] : (nums2[a2 + k - 1] + nums2[a2 + k]) * 1.0 / 2;
if (a2 >= nums2Size) return flag ? nums1[a1 + k - 1] : (nums1[a1 + k - 1] + nums1[a1 + k]) * 1.0 / 2;
}
if (flag) {
if (a1 >= nums1Size) return nums2[a2];
else if (a2 >= nums2Size) return nums1[a1];
else return nums1[a1] > nums2[a2] ? nums2[a2] : nums1[a1];
}
if (nums1[a1] > nums2[a2]) {
if (a2 + 1 >= nums2Size) return (nums1[a1] + nums2[a2]) * 1.0 / 2;
if (nums2[a2 + 1] < nums1[a1]) return (nums2[a2] + nums2[a2 + 1]) * 1.0 / 2;
return (nums1[a1] + nums2[a2]) * 1.0 / 2;
} else {
if (a1 + 1 >= nums1Size) return (nums1[a1] + nums2[a2]) * 1.0 / 2;
if (nums1[a1 + 1] < nums2[a2]) return (nums1[a1] + nums1[a1 + 1]) * 1.0 / 2;
return (nums1[a1] + nums2[a2]) * 1.0 / 2;
}
}
复杂度: 假设两个数组长度为m, n, 由于使用二分查找, 复杂度为O(log(m + n))
LeetCode第5题: 寻找最长回文子串
解法一:
这个解法是我以前的代码, 具体思路如下
- 从最长字符开始寻找, 往短的方向寻找, 这样如果找到即可返回, 如果从最短开始, 由于不知道是否是最大的, 那么继续寻找
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
if s == "":
return ""
if len(s) == 1:
return s
i = 0
j = len(s)
str = ""
while len(str) < (j - i + 1):
while len(str) < (j - i + 1):
j = s.rfind(s[i], i, j)
if len(str) < (j - i + 1) and s[i:j] == s[j:i:-1]:
str = s[i:j+1]
j = len(s)
i += 1
return str
复杂度分析: 本算法相当于暴力破解, 在最好的情况需要一次, 最坏情况需要n的平方次
解法二:
马拉车算法
- 马拉车算法核心思想: 用过去的求过的的最长回文子串加速未知的, 本质是动态规划
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
s = s.replace("", "#") # 将字符串马拉车化
c = -1 # 初始化对称中心
r = -1 # 初始化最小右边界
max1 = 0 # 记录最大右边界
cmax = c # 记录最大边界半径
arr = [0] * (len(s) - 1)
# 遍历字符串
for i in range(0, len(s) - 1):
# 核心加速代码: 可以直接根据i'的边界半径求出i点的在r内的边界半径
arr[i] = min(r - i, arr[2 * c - i]) if r > i else 1
# 继续扩展i的边界半径
while (i + arr[i] < len(s) and i - arr[i] > -1):
if s[i + arr[i]] == s[i - arr[i]]:
arr[i] += 1
else:
break
# 如果i的边界半径大于已经记录的边界半径, 那么就更新边界半径和对称中心
if arr[i] > max1:
max1 = arr[i]
cmax = i
# 更新边界半径和对称中心
if arr[i] + i > r:
r = i + arr[i]
c = i
str = s[cmax - max1 + 1: cmax + max1 - 1]
print(cmax, max1)
print(str)
return str.replace("#", "")