300分钟面试精选题记录1 无重复字符的最长字串 寻找两个有序数组的中位数 合并k个排序链表

3.无重复字符的最长字串

在这里插入图片描述
暴力法把所有子串都找出来,一共是 n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2种,(不算空字符串)
另外,长度为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的时候条件判断的顺序不要搞错了。

解法二 最小堆
换个思路,其实只需要每次从所有链表中找出第一个也就是最小的那个。可以用最小堆来做
在这里插入图片描述

解法三 分治法
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值