LeetCode0004

  • 给定两个大小为 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];
}
}
}

LeetCode0007

  • 给出一个 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的更多相关文章

  1. 我为什么要写LeetCode的博客?

    # 增强学习成果 有一个研究成果,在学习中传授他人知识和讨论是最高效的做法,而看书则是最低效的做法(具体研究成果没找到地址).我写LeetCode博客主要目的是增强学习成果.当然,我也想出名,然而不知 ...

  2. LeetCode All in One 题目讲解汇总(持续更新中...)

    终于将LeetCode的免费题刷完了,真是漫长的第一遍啊,估计很多题都忘的差不多了,这次开个题目汇总贴,并附上每道题目的解题连接,方便之后查阅吧~ 477 Total Hamming Distance ...

  3. [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 ...

  4. 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 ...

  5. Leetcode 笔记 112 - Path Sum

    题目链接:Path Sum | LeetCode OJ Given a binary tree and a sum, determine if the tree has a root-to-leaf ...

  6. Leetcode 笔记 110 - Balanced Binary Tree

    题目链接:Balanced Binary Tree | LeetCode OJ Given a binary tree, determine if it is height-balanced. For ...

  7. Leetcode 笔记 100 - Same Tree

    题目链接:Same Tree | LeetCode OJ Given two binary trees, write a function to check if they are equal or ...

  8. Leetcode 笔记 99 - Recover Binary Search Tree

    题目链接:Recover Binary Search Tree | LeetCode OJ Two elements of a binary search tree (BST) are swapped ...

  9. Leetcode 笔记 98 - Validate Binary Search Tree

    题目链接:Validate Binary Search Tree | LeetCode OJ Given a binary tree, determine if it is a valid binar ...

  10. Leetcode 笔记 101 - Symmetric Tree

    题目链接:Symmetric Tree | LeetCode OJ Given a binary tree, check whether it is a mirror of itself (ie, s ...

随机推荐

  1. 关于python请求库Selenium安装所遇到的问题

    今天,初次接触python,在网上买了一本关于爬虫的书,因为之前电脑上存在python,所以就对着书直接进行的请求库的安装,安装的时候,主要遇到了下边一个问题,在安装Selenium的时候,出现以下提 ...

  2. Java - 记录String中intern()方法的学习与理解

    intern()方法:把堆中的引用丢入常量池中,然后返回这个引用.当常量池中已经存在这个引用,就直接返回这个引用.(jdk1.8) 由于jdk1.7中将字符串常量池改为存放在堆中,因此intern() ...

  3. 吴裕雄--天生自然Linux操作系统:Linux 远程登录

    Linux一般作为服务器使用,而服务器一般放在机房,你不可能在机房操作你的Linux服务器. 这时我们就需要远程登录到Linux服务器来管理维护系统. Linux系统中是通过ssh服务实现的远程登录功 ...

  4. UML-类图-需要写关联名称吗?

    概念模型:需要写关联名称:类图:不需要写关联名称. 注意,概念模型关联线不需要箭头.

  5. Python—使用列表构造栈数据结构

    class Stack(object): """ 使用列表实现栈 """ def __init__(self): self.stack = ...

  6. 远程SSH服务使用指南

    Author Email Yaoyao Liu yaoyaoliu@msn.com 本文所有教程以ubuntu为例,对其他unix内核系统如Debian.CentOS.macOS等也适用. 目录 安装 ...

  7. idea中maven项目依赖jar一直标红线

    网上maven仓库中无法下载某些jar包,这时候就需要手动下载,并导入maven, 导入命令demo: mvn install:install-file -DgroupId=javax.media - ...

  8. 主流消息队列rocketMq,rabbitMq比对使用

    首先整理这个文章是因为我正好有机会实战了一下rocketmq,阿里巴巴的一个开源消息中间件.所以就与以往中rabbitmq进行小小的比较一下.这里主线的根据常见面试问题进行整理. 一.消息队列常用的场 ...

  9. 脚本kafka-configs.sh用法解析

    引用博客来自李志涛:https://www.cnblogs.com/lizherui/p/12275193.html 前言介绍 网络上针对脚本kafka-configs.sh用法,也有一些各种文章,但 ...

  10. [前端] VUE基础 (5) (过滤器、生命周期、钩子函数)

    一.过滤器 过滤器分为局部过滤器和全局过滤器. 1.局部过滤器 <body> <div id="app"> </div> <script ...