LeetCode(2)

寻找两个有序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2

请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。

你可以假设 nums1 和 nums2 不会同时为空。

示例 1:

nums1 = [1, 3]
nums2 = [2]

则中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

则中位数是 (2 + 3)/2 = 2.5

思路:

两个数组的总长度分别为m,n,求两个数值的中位数,可以把问题归结为求两个有序数组的第k个值的大小,如果m+n为奇数,直接求第mid个数的大小,如果m+n为偶数,则求第中间位的的平均值,运用了分治的方法

class Solution {
public:
	double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {

		// 找两向量中最中间的一个或两个数
		int k = (nums1.size() + nums2.size() + 1) / 2;
		double fMid = getKth(nums1, 0, nums1.size() - 1, nums2, 0, nums2.size() - 1, k);
		if ((nums1.size() + nums2.size()) % 2 == 1)
			return fMid;
		else
			return (fMid + getKth(nums1, 0, nums1.size() - 1, nums2, 0, nums2.size() - 1, k + 1)) / 2;
	}

	double getKth(vector<int>& nums1, int l1, int r1, vector<int>& nums2, int l2,int r2, int k)
	{
		if (l1 > r1)
			return nums2[l2 + k - 1];
		if (l2 > r2)
			return nums1[l1 + k - 1];

		int m1 = l1 + (r1 - l1) / 2;
		int m2 = l2 + (r2 - l2) / 2;

		int halfLen = m1 - l1 + m2 - l2 + 2;
		if (nums1[m1] < nums2[m2])
			if (halfLen > k)
				return getKth(nums1, l1, r1, nums2, l2, m2 - 1, k);
			else
				return getKth(nums1, m1 + 1, r1, nums2, l2, r2, k - (m1 - l1 + 1));
		else
			if (halfLen > k)
				return getKth(nums1, l1, m1 - 1, nums2, l2, r2, k);
			else
				return getKth(nums1, l1, r1, nums2, m2 + 1, r2, k - (m2 - l2 + 1));
	}
};

结果: 

 

最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

示例 2:

输入: "cbbd"
输出: "bb"

思路:

 顺序遍历给定字符串,遍历到的每个位置都有可能为回文中心,此时有两种情况:
一种情况是,当回文串为奇数时,直接以当前字符为中心,向前驱与后继扩展。
第二种情况是,当回文串为偶数时,以当前字符与当前字符的后继的中间位置为中心,向前驱与后继扩展。

奇数回文串n个位置,偶数回文串(n-1)个位置,共有2n-1个位置

时间复杂度,2n-1个位置与以每个位置为中心的向前向后访问,复杂度为O(n^2)。

class Solution {
public:
	string longestPalindrome(string s) {
        if (s == "")
            return "";
		int maxLen = 0;
		int centerIndex = -1;
		for (int i = 0; i < s.length(); ++i)
		{
			int len1 = CenterExtension(s, i, i);
			int len2 = CenterExtension(s, i, i + 1);
			int tempMaxLen = max(len1, len2);
			if (centerIndex == -1 || maxLen < tempMaxLen)
			{
				maxLen = tempMaxLen;
				centerIndex = i;
			}
		}
		return s.substr(centerIndex - (maxLen - 1) / 2, maxLen);
	}

	int CenterExtension(string s, int left, int right)
	{
		int L = left;
		int R = right;

		while (L >= 0 && right < s.length() && s[L] == s[R])
		{
			L--;
			R++;
		}
		return R - L - 1;
	}
};

结果:

Z字形变换

将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下:

L   C   I   R
E T O E S I I G
E   D   H   N

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"LCIRETOESIIGEDHN"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入: s = "LEETCODEISHIRING", numRows = 3
输出: "LCIRETOESIIGEDHN"

示例 2:

输入: s = "LEETCODEISHIRING", numRows = 4
输出: "LDREOEIIECIHNTSG"
解释:

L     D     R
E   O E   I I
E C   I H   N
T     S     G

思路:

将Z字变换看成是V字变换,除去V的起点,其余点都以V的顶点对称,以顶点的下标向-1与+1扩散,与对应的行也能相匹配。

当最后一个V字形不完整时,计算时按照完整的来计算,当计算所得下标超出所给字符串最大下标时,不放进每行对应的字符串内。

最后将每行字符串拼接。

class Solution {
public:
    string convert(string s, int numRows) {
        if (s.empty())
            return "";
        if (numRows == 1)
			return s;
  		// 每个Z是3 * numRows - 2
		// 可以将Z看成是V排序,每个V的长度是,2 * numRows - 2
		const int VLen = 2 * numRows - 2;
		const int size = s.length();
		const int numV = size / VLen + 1;
		// 第一行始终是i * VLen;
		// 第numRows行始终是i * VLen + numRows - 1
		// 中间的就是
		vector<string> zstr(numRows, "");
		for (int j = 0; j < numV; ++j)
		{
			int LBIndex = j * VLen;
			if (LBIndex < size)
				zstr[0].push_back(s[LBIndex]);

			int LEIndex = j * VLen + numRows - 1;
			if (LEIndex < size)
				zstr[numRows - 1].push_back(s[j * VLen + numRows - 1]);

			// 基准点为最后一行
			for (int i = 1; i <= numRows - 2; ++i)
			{
				// 第j * VLen + numRows - 1行
				if (LEIndex - i < size)
					zstr[numRows - 1 - i].push_back(s[LEIndex - i]);
				if (LEIndex + i < size)
					zstr[numRows - 1 - i].push_back(s[LEIndex + i]);
			}
		}

		string rel;
		for (int i = 0; i < numRows; ++i)
			rel += zstr[i];

		return rel;
    }
};

结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值