LeetCode Day 2
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
思路:
- 时间复杂度若为O(m+n)的话,先确定nums1和nums2是增序还是倒序;
- 增序的让指针指向头从头到尾读数据,倒序的话让指针指向末尾,从后往前读;
- 比较当前读到的两个数值,总是优先将小的那个压入临时数组temp;
- 判断temp个数是奇数还是偶数,返回相应的中位数即可。
//这里我们默认俩数组都是增序,我们先按这个思路提交一下看看是否Accept,测试一下leetcode
var findMedianSortedArrays = function (nums1, nums2) {
//题目设定nums1和nums2不会同时为空
if (nums1) {
if (nums2) {
let i = 0, j = 0, lens1 = nums1.length, lens2 = nums2.length;
let tmp = [];
while (i < lens1 && j < lens2) {
if (nums1[i] < nums2[j]) {
tmp.push(nums1[i]);
i++;
}
else {
tmp.push(nums2[j])
j++;
}
}
if (i < lens1) {
tmp = tmp.concat(nums1.slice(i));
}
if (j < lens2) {
tmp = tmp.concat(nums2.slice(j));
}
let totalLen = lens1 + lens2;
if (totalLen % 2 === 0) {
return (tmp[totalLen / 2 - 1] + tmp[totalLen / 2]) / 2;
}
else {
return tmp[Number.parseInt(totalLen / 2)];
}
}
else {
let lens1 = nums1.length;
if (lens1 % 2 === 0) {
return (nums1[lens1 / 2 - 1] + nums1[lens1 / 2]) / 2;
}
else {
return nums1[Number.parseInt(lens1 / 2)];
}
}
}
else {
let lens2 = nums2.length;
if (lens2 % 2 === 0) {
return (nums2[lens2 / 2 - 1] + nums2[lens2 / 2]) / 2;
}
else {
return nums2[Number.parseInt(lens2 / 2)];
}
}
};
结果:
- emm,虽然过了,但追求Perfect的我们肯定不能简单的就这么过了。
思路二:
- 想让时间复杂度为logn,我们一般考虑二分算法。
- 求中位数,其实就是求第k小的数的一种特殊情况,假设我们要找第k小的数,我们可以每次循环排除掉k/2个数。比较两个数组的第k/2个数字,如果k是奇数,向下取整。
- 两个有序数组的中位数即为:1、两个数组长度(m+n)为奇数,求第(m+n+1)/2小元素;2、两个数组长度(m+n)为偶数,求第(m+n)/2小、第(m+n)/2+1小数字两者的平均值。
- 规律:A[1] ,A[2] ,A[3],A[k/2] ... ,B[1],B[2],B[3],B[k/2] ... ,如果 A[k/2]<B[k/2] ,那么A[1],A[2],A[3],A[k/2]都不可能是第k小的数字。
- 这是因为,在A 数组中,比 A[k/2] 小的数有k/2-1个,而对于B数组而言,已知A[k/2]小于B[k/2],就算除了B[k/2],它前边的数字都比 A[k/2] 小,也只有k/2-1个数,所以比 A[k/2] 小的数字最多有 k/2-1+k/2-1=k-2个,所以 A[k/2] 最多是第 k-1 小的数。而比 A[k/2] 小的数更不可能是第k小的数了,所以可以A[1],A[2]...A[k/2]都排除掉。
- 我们每次都是取k/2的数进行比较,有时候可能会遇到数组长度小于k/2的时候,此时将箭头指向数组末尾就可以了。采用递归的思路,每次比较min(k/2,len(数组)) 对应的数字,把小的那个对应的数组的数字排除,将两个新数组进入递归,并且k要减去排除的数字的个数。递归终止的条件为k=1或者某一个数组为空,此时找非空数组的第k个值即可。
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var findMedianSortedArrays = function (nums1, nums2) {
// 题目设定nums1和nums2不会同时为空
let totalLen = (nums1 ? nums1.length : 0) + (nums2 ? nums2.length : 0);
if (totalLen % 2 === 0) {
// 偶数则要返回第K个和第K+1个
// 因为我在函数里使用的是shift和splice操作,会影响源数组
// 所以找出第K个之后,两个数组中最小k个数就已经都被排除掉了
// 想找俩数组中第k+1个,只要在后续的俩数组中找第一个最小数即可
return (findKthNumberArrays(nums1, nums2, totalLen / 2) + findKthNumberArrays(nums1, nums2, 1)) / 2;
}
else {
//奇数直接返回第K个即可
return findKthNumberArrays(nums1, nums2, (totalLen + 1) / 2);
}
};
function findKthNumberArrays(nums1, nums2, k) {
if (k === 1) {
//不可能存在两者都为空的情况
if (nums1 && nums1.length > 0) {
if (nums2 && nums2.length > 0) {
//弹出两者小的那一个,大的那一个要留着以便二次比较
if (nums1[0] > nums2[0]) {
return nums2.shift();
} else {
return nums1.shift();
}
}
else {//nums1不为空,num2为空
return nums1.shift();
}
} else {//nums1为空,nums2不空
return nums2.shift();
}
}
else {
//不可能存在两者都为空的情况
if (nums1 && nums1.length > 0) {
if (nums2 && nums2.length > 0) {
let interval = Math.floor(k / 2);
// 小的那个数组移除掉k/2个数
// 再找新数组中第k-interval小的数即可
// 要注意K/2可能会比数组本身长度大的多,因此数组不一定取得到k/2-1的值,此时取数组最大值即可
let digit1 = interval > nums1.length ? nums1[nums1.length - 1] : nums1[interval - 1];
let digit2 = interval > nums2.length ? nums2[nums2.length - 1] : nums2[interval - 1];
if (digit1 > digit2) {
interval = Math.min(nums2.length, interval);
nums2.splice(0, interval);
return findKthNumberArrays(nums1, nums2, k - interval);
}
else {
interval = Math.min(nums1.length, interval);
nums1.splice(0, interval);
return findKthNumberArrays(nums1, nums2, k - interval);
}
}
else {//nums2为空,返回nums1中第k个即可,因为是有序数组,第k小也就是第k个数前面k个小数要排除掉以便后续操作
let tmp = nums1.splice(0, k);
return tmp[k - 1];
}
}
else {//nums1为空,循环结束,返回num2中第k个即可,与上面nums1一样的操作
let tmp = nums2.splice(0, k);
return tmp[k - 1];
}
}
}
- 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
- 假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
- 这题目用Javascript做反而凸显不出题目的必要性,因为Number是浮点数,上下限都远大于231,建议用带int类型并且int类型是32位的语言做,如C#。
/**
* @param {number} x
* @return {number}
*/
var reverse = function(x) {
let maxValue = - 1 - (2 << 30);
let minValue = 2 << 30;
if (x > 0) {
let strX = x + '';
let arr = [];
for (let lens = strX.length, i = lens - 1; i > -1; i--) {
arr.push(strX[i]);
}
let result = Number.parseInt(arr.join(''));
if (result > maxValue) {
return 0;
}
return result;
}
if (x < 0) {
let strX = x + '';
let arr = [];
for (let lens = strX.length, i = lens - 1; i > 0; i--) {
arr.push(strX[i]);
}
let result = 0 - Number.parseInt(arr.join(''));
if (result < minValue) {
return 0;
}
return result;
}
return 0;
};
C#版本
public int Reverse(int x)
{
int result = 0;
int remainder = 0;
//int.MaxValue = 2147483647
//int.MinValue = -2147483648
int topLimit = int.MaxValue / 10;//2147483640
int botLimit = int.MinValue / 10;//-2147483640
while (x!=0)
{
remainder = x % 10;
if (result > topLimit || (result == topLimit && remainder > 7)) return 0;
if (result < botLimit || (result == botLimit && remainder < -8)) return 0;
result = result * 10 + remainder;
x /= 10;
}
return result;
}
在项目->属性->生成->高级中开启算数“溢出检查”,我们可以省去两层if判断,改用checked关键字来检查溢出,代码可以改成这样:
public class Solution
{
public int Reverse(int x)
{
int result = 0;
int remainder = 0;
while (x != 0)
{
remainder = x % 10;
try
{
result = checked(result * 10 + remainder);
}
catch (OverflowException e)
{
return 0;
}
x /= 10;
}
return result;
}
}
参考资料:
LeetCode Day 2的更多相关文章
- 我为什么要写LeetCode的博客?
# 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...
- LeetCode All in One 题目讲解汇总(持续更新中...)
终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...
- [LeetCode] Longest Substring with At Least K Repeating Characters 至少有K个重复字符的最长子字符串
Find the length of the longest substring T of a given string (consists of lowercase letters only) su ...
- Leetcode 笔记 113 - Path Sum II
题目链接:Path Sum II | LeetCode OJ Given a binary tree and a sum, find all root-to-leaf paths where each ...
- Leetcode 笔记 112 - Path Sum
题目链接:Path Sum | LeetCode OJ Given a binary tree and a sum, determine if the tree has a root-to-leaf ...
- Leetcode 笔记 110 - Balanced Binary Tree
题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...
- Leetcode 笔记 100 - Same Tree
题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...
- Leetcode 笔记 99 - Recover Binary Search Tree
题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...
- Leetcode 笔记 98 - Validate Binary Search Tree
题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...
- Leetcode 笔记 101 - Symmetric Tree
题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...
随机推荐
- 将QT窗口嵌入到WinForm窗口
要想 windows下抓取Qt进程主界面,并嵌入到自己的程序中显示,需要首先设置qt窗口的windowTitle属性,然后就可以通过 windows api 中的 FindWindow 函数查找到窗口 ...
- go语言实现leetcode-242
package main import ( "fmt" "reflect" ) func isAnagram(s string, t string) bool ...
- Python对象赋值、浅拷贝、深拷贝
Python中,基本数据类型,理解为常见数据类型:布尔型.整型.浮点型.字符串.列表.元组.字典.集合,随语言不同而不同,但是根据在内存中存储方式的不同,区分开原子类型和容器类型. 对象赋值 对象的赋 ...
- 去掉select在苹果手机上的原生样式
outline: none; -webkit-appearance: none; 该属性会去掉select所有的默认样式,包括下拉箭头,因此需要通过额外的样式控制下拉箭头
- 前端Json 增加,删除,修改元素(包含json数组处理)
一:基础JSON对象 二:JSON数组数据 以下为增删修改方法: <!DOCTYPE html> <html lang="en"> <head> ...
- c语言中assert的用法
/************************************************************************* > File Name: assert.c ...
- UML-如何画SSD?
1.SSD来自哪里?答:用例文本 2.如何为系统事件和操作命名? 3.SSD中的哪些需要放到词汇表中? SSD元素包含 1).操作名称 2).参数 3).返回数据 这些元素,必须要简洁.但别人可能不太 ...
- JavaSE--类加载器
参考:http://www.importnew.com/6581.html Java 编译器会为虚拟机转换源指令.虚拟机代码存储在以 .class 为扩展名的类文件中,每个类文件都包含某个类或者接口的 ...
- JavaScript详解(一)
简介: Javascript是一个脚本语言,弱类型的编程语言,简称js,被称为网站开发的行为.它的作用是增加页面特效.前后台交互以及应用于后台开发.它即可写在HTML的script标签里,也可写在外部 ...
- 第2章 Innodb 存储引擎
一.InnoDB 体系架构 1.1后台线程 master thread:刷新内存中的数据到磁盘 io thread:处理 IO 请求,AIO purge thread:清理undo 页的回收 page ...