3.无重复字符的最长字串
暴力法把所有子串都找出来,一共是
种,(不算空字符串)
另外,长度为n的字符串有多少子序列?子序列是不用在原字符串中相邻的。:
时间复杂度:O(n^3)
快慢指针
有一个快指针,一个慢指针,慢指针检查集合中该元素存不存在,不存在则放入,存在的话,慢指针右移,同时拿出集合中慢指针每次指向的元素,直到快指针指向元素可以放到集合中去。
时间复杂度:O(n)
空间复杂度:O(n)
4.寻找两个有序数组的中位数
解法一
- 利用归并排序思想将它们合并成一个长度为m+n的有序数组
- 合并的时间复杂度为m+n,从中选取中位数,整体复杂度为O(m+n)>O(log(m+n))
解法二切分法
问题转变为从两个有序数组中寻找第k小的数fk)
- L是奇数时,令k=L/2结果为f(k+1)
- L是偶数时,结果为(f(k)+f(k+1))/2
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m=nums1.size();
int n=nums2.size();
int k=(m+n)/2;
if((m+n)%2==1)//总个数是奇数,返回中间的数
{
return findKth(nums1,0,m-1,nums2,0,n-1,k+1);
}
else{//总个数是偶数,返回中间两个数的平均值
return(
findKth(nums1,0,m-1,nums2,0,n-1,k)+
findKth(nums1,0,m-1,nums2,0,n-1,k+1))/2.0;
}
}
//查找第k小的元素
double findKth(vector<int> nums1,int l1,int h1,vector<int> nums2,int l2,int h2,int k){
int m=h1-l1+1;
int n=h2-l2+1;
//nums1数组长度大于nums2 互换,加快程序结束
if(m>n){
return findKth(nums2,l2,h2,nums1,l1,h1,k);
}
//如果nums1数组的长度为0,直接返回nums2里第k小的数
if(m==0){
return nums2[l2+k-1];
}
if(k==1){
return min(nums1[l1],nums2[l2]);
}
//分别选两个数组的中间数
int na=min(k/2,m);
int nb=k-na;
int va=nums1[l1+na-1];
int vb=nums2[l2+nb-1];
//比较两者大小
if(va==vb){//相等表示中位数已经找到,返回该值
return va;
}else if(va<vb){//不等范围缩小继续搜索
return findKth(nums1,l1+na,h1,nums2,l2,l2+nb-1,k-na);
}else{
return findKth(nums1,l1,l1+na-1,nums2,l2+nb,h2,k-nb);
}
}
};
23 合并k个排序链表
最直观思路
把链表中的数拿出来,归并或快速排序后再放到一个链表中返回:
class Solution {
public:
ListNode* mergeKLists(vector<ListNode*>& lists) {
vector<int> nums;
for (int i = 0; i < lists.size(); i++) {
while (lists[i]) {
nums.push_back(lists[i]->val);
lists[i] = lists[i]->next;
}
}
if (nums.size() == 0) return nullptr;
//将num排序
sort(nums, 0, nums.size() - 1);
//将num转化为链表
ListNode * head = new ListNode(nums[0], nullptr);
ListNode * p = head;
for (int i = 1; i < nums.size(); i++) {
ListNode *temp = new ListNode(nums[i], nullptr);
p->next = temp;
p = temp;
}
return head;
}
void sort(vector<int>& nums, int low,int high) {
if (low >= high)return;
int mid = low + (high - low) / 2;
sort(nums, low, mid);
sort(nums, mid + 1, high);
merge(nums, low, mid, high);
}
void merge(vector<int>& nums, int low, int mid, int high) {
int k = low, i = low, j = mid + 1;
vector<int> copy = nums;
while (k <= high) {
//边界判断写前面很重要 不然i j没有限制
if (i > mid) {
nums[k++] = copy[j++];
}
else if(j>high) {
nums[k++] = copy[i++];
}
else if (copy[j] < copy[i]) {
nums[k++] = copy[j++];
}
else {
nums[k++] = copy[i++];
}
}
}
};
这个虽然笨,但是leetcode是通过的:对这一题通过的要求很松
时间复杂度和排序一样,如果k个链表,每个链表n个节点,时间复杂度为O(nk*log(nk))
这个就注意两个点,一个是空链表的特殊情况处理,一个是merge的时候条件判断的顺序不要搞错了。
解法二 最小堆
换个思路,其实只需要每次从所有链表中找出第一个也就是最小的那个。可以用最小堆来做
解法三 分治法
扫描二维码关注公众号,回复:
11496150 查看本文章