【题1】二维数组中的查找
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:(1)矩阵是有序的,从左向右递增,从上向下递减;
(2)从左下角开始查找,比目标值大的,向上找;比目标值小的,向右找。
function Find(target, array)
{
let rows = array.length;
let columns = array[0].length;
for (var j = 0, i = rows - 1; i >= 0 && j < columns;) {
if (array[i][j] == target) {
return true
} else if (array[i][j] > target) {
i--;
continue
} else if (array[i][j] < target) {
j++
continue
}
}
return false
}
【题2】替换空格
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
function replaceSpace(str)
{
// 首先将字符串转换为数组["We", "Are", "Happy"]
let array = str.split(' ')
for (var i = 0; i < array.length - 1; i++) {
// 将%20添加进去["We%20", "Are%20", "Happy"]
array[i] = array[i] + "%20"
}
// 数组转换为字符串
let arr = array.join('')
return arr
}
牵扯到一个问题,使用正则表达式将逗号删除
function replaceSpace(str)
{
// 首先将字符串转换为数组["We", "Are", "Happy"]
let array = str.split(' ')
for (var i = 0; i < array.length - 1; i++) {
// 将%20添加进去["We%20", "Are%20", "Happy"]
array[i] = array[i] + "%20,"
}
// 数组转换为字符串
let arr = array.join('')
// 由于字符串中带了逗号We%20,Are%20,Happy,使用正则表达式将逗号删除We%20Are%20Happy
array = arr.replace(/^,/g,'')
return array
}
其他人的好的方式
// \s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
// 直接遍历字符串,遇到空格就替换。
return str.replace(/\s/g,'%20')
return str.split(" ").join("%20")
【题3】从尾到头打印链表
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
/*function ListNode(x){
this.val = x;
this.next = null;
}*/
function printListFromTailToHead(head)
{
let array = []
let start = head
while(start) {
array.push(start.val)
start = start.next
}
return array.reverse()
}
【题4】计算1+2+3+…………+n
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
基于此,采用短路求值原理:
“||”运算符表示或,有一个为真则结果为真,前半部分判断出为真之后,不用继续考虑后半部分,最终结果为真;
“&&”运算符表示与,有一个为假则结果为假,前半部分判断出为假之后,不用考虑后半部分,最终结果为假。
利用上述原理,可以进行递归运算。
function Sum_Solution(n)
{
var ans = n
ans && (ans += Sum_Solution(n-1))
return ans
}
【题5】写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
- 两个数异或:相当于每一位相加,而不考虑进位;
- 两个数相与,并左移一位:相当于求得进位;
- 将上述两步的结果相加
function Add(num1, num2)
{
while(num2 != 0) {
var sum = num1 ^ num2 // 两数相加,不考虑进位
var num3 = (num1&num2) << 1 // 进位
num1 = sum
num2 = num3
}
return num1
}
13+11 = ?;
13 的二进制 1 1 0 1 -----a 13
11 的二进制 1 0 1 1 -----b 11
(a&b)<<1 -> 1 0 0 1 0 -----d 18
a^b -> 0 1 1 0 -----e 6
(d&e)<<1 -> 0 0 1 0 0 ------f 4
d^e -> 1 0 1 0 0 -----g 20
(f&g)<<1 -> 0 10 0 0 ------h 8
f^g -> 1 0 0 0 0 ------i 16
(h&i)<<1 -> 0 0 0 0 0 ------h 0 ------------退出循环
h^i -> 1 1 0 0 0 ------i 24
【题6】输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
function NumberOf1(n)
{
//js中负数使用二进制补码的形式存储
if (n<0) {
//无符号右移将负数的二进制码当成正数的二进制码
n = n >>> 0
}
// n.toString(2)转化成二进制数,n.toString(2).split('1'),n为16打印结果["", "00000"]
var arrN = n.toString(2).split('1')
return arrN.length-1
}
【题7】在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
function duplicate(numbers, duplication)
{
//这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
//函数返回True/False
if (numbers.length === 0 || numbers.length ===1) {
return false
}
for (var i = 0; i < numbers.length -1; i++) {
for (var j = numbers.length-1; j > i; j--) {
if (numbers[i] === numbers[j]) {
duplication[0] = numbers[i]
return true
}
}
}
return false
}
【题8】给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
function Power(base, exponent)
{
return Math.pow(base, exponent)
}
function Power(base, exponent)
{
return base**exponent
}
【题9】斐波那契数列
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
斐波那契数列:兔子数列
在第一个月有一对刚出生的小兔子,在第二个月小兔子变成大兔子并开始怀孕,第三个月大兔子会生下一对小兔子,并且以后每个月都会生下一对小兔子。 如果每对兔子都经历这样的出生、成熟、生育的过程,并且兔子永远不死,那么兔子的总数是如何变化的?
我们把这个数列列表
我们发现会发现以下几个规律:
前一个月的大兔子对数就是下一个月的小兔子对数。前一个月的大兔子和小兔子对数的和就是下个月大兔子的对数。
按照这个表格,我们会发现无论是小兔子对数、大兔子对数还是总对数,除了最初几个数字不一样之外,后面都是按照1、1、2、3、5、8、13…变化的,这个数列就称为兔子数列或者斐波那契数列。
兔子数列最大的特点就是前两项之和等于后一项,比如1+1=2、1+2=3、2+3=5、3+5=8、5+8=13…
我们用an表示一个数列的第n项,那么斐波那契数列的规律就是
这种式子称为递推式,也就是说可以从前面一项或几项,计算出后面一项的式子。再结合前两项a1=a2=1,就可以得到后面任意一项了。
function Fibonacci(n)
{
if (n === 0) {
return 0
}
if (n === 1 || n === 2) {
return 1
}
return Fibonacci(n-1) + Fibonacci(n-2)
}
function Fibonacci(n)
{
if (n === 0) {
return 0
}
if (n === 1 || n === 2) {
return 1
}
if (n === 3) {
return 2
}
return 3*Fibonacci(n-3) + 2*Fibonacci(n-4)
}
【题】一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
function jumpFloor(number)
{
if(number === 0) {
return 0
} else if (number === 1) {
return 1
} else if (number === 2) {
return 2
}
var arr = []
arr[0] = 1
arr[1] = 1
arr[2] = 2
for (var i = 3; i <= number; i++) {
arr[i] = arr[i - 1] + arr[i - 2]
}
return arr[number]
}
【题】一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
function jumpFloorII(number)
{
if (number === 0) {
return 0
} else if (number === 1) {
return 1
} else if (number === 2) {
return 2
} else {
return 2*jumpFloorII(number-1)
}
}
【题10】旋转数组的最小数
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
function minNumberInRotateArray(rotateArray)
{
if (rotateArray.length === 0) {
return 0
}
for (var i = 0; i < rotateArray.length - 1; i++) {
for (var j = 0; j < rotateArray.length - i - 1; j++) {
if (rotateArray[j] > rotateArray[j+1]) {
var tmp = rotateArray[j]
rotateArray[j] = rotateArray[j+1]
rotateArray[j+1] = tmp
}
}
}
return rotateArray[0]
}
function minNumberInRotateArray(rotateArray)
{
if (rotateArray.length === 0) {
return 0
}
rotateArray.sort(function (a, b) {
return a-b
})
return rotateArray[0]
}
【题11】数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
首先,我想到的是挨个遍历的方式,毫无疑问,在数组长度较大的时候,会出现运行时间慢的问题,且复杂度高,导致运行不通过。代码如下:
function InversePairs(data)
{
// write code here
var count = 0
for (var i = 0; i < data.length; i++) {
for (var j = i+1; j < data.length; j++) {
if (data[i] > data[j]) {
count++
}
}
}
return count%1000000007
}
不通过
您的代码已保存
运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
case通过率为50.00%
另:基于归并排序的方式,
归并排序代码如下:
function merge(left, right){
var result=[];
while(left.length>0 && right.length>0){
if(left[0]<right[0]){
/*shift()方法用于把数组的第一个元素从其中删除,并返回第一个元素的值。*/
result.push(left.shift());
}else{
result.push(right.shift());
}
}
return result.concat(left).concat(right);
}
function mergeSort(items){
if(items.length == 1){
return items;
}
var middle = Math.floor(items.length/2),
left = items.slice(0, middle),
right = items.slice(middle);
return merge(mergeSort(left), mergeSort(right));
}
var items = [5,6,2,1,3,8,1,9,6,100]
document.write(mergeSort(items))
下述方式是基于归并排序,可顺利通过:
先把数组分割成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对的过程中,还需要对数组进行排序。
function InversePairs(data)
{
if(!data || data.length < 2) return 0;
var copy = data.slice(),
count = 0;
count = mergeSort(data, copy, 0, data.length-1);
return count%1000000007;
}
function mergeSort(data, copy, start, end){
if(end === start) return 0;
var mid = (end-start)>>1,
left = mergeSort(copy, data, start,start + mid),
right = mergeSort(copy, data, start + mid + 1, end),
count = 0,
p = start + mid,//前一个数组的最后一个下标
q = end,//后一个数组的下标
copyIndex = end;//辅助数组下标,从最后一个算起
while(p >= start && q >= start + mid + 1){
if(data[p] > data[q]){
count += q - start - mid;
copy[copyIndex--] = data[p--];
}else{
copy[copyIndex--] = data[q--];
}
}
while(p >= start){
copy[copyIndex--] = data[p--];
}
while(q>=start+mid+1){
copy[copyIndex--] = data[q--];
}
return left+right+count;
}
【题12】字符串的排列(本题知识点:字符串、动态规划、递归)
题目描述
输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
方法一:递归算法
/*思路:递归法,问题转换为先固定第一个字符,求剩余字符的排列;求剩余字符排列时跟原问题一样。
(1) 遍历出所有可能出现在第一个位置的字符(即:依次将第一个字符同后面所有字符交换);
(2) 固定第一个字符,求后面字符的排列(即:在第1步的遍历过程中,插入递归进行实现)。
需要注意的几点:
(1) 先确定递归结束的条件,例如本题中可设begin == str.size() - 1;
(2) 形如 aba 或 aa 等特殊测试用例的情况,vector在进行push_back时是不考虑重复情况的,需要自行控制;
(3) 输出的排列可能不是按字典顺序排列的,可能导致无法完全通过测试用例,考虑输出前排序,或者递归之后取消复位操作。*/
https://blog.youkuaiyun.com/wzy_1988/article/details/8939140
这是典型的递归求解问题,递归算法有四个特性:
必须有可达到的终止条件,否则程序陷入死循环
子问题在规模上比原问题小
子问题可通过再次递归调用求解
子问题的解应能组合成整个问题的解
对于字符串的排列问题:
如果能生成n-1个元素的全排列,就能生成n个元素的全排列。对于只有一个元素的集合,可以直接生成全排列。所以全排列的递归终止条件很明确,只有一个元素时。我们可以分析一下全排列的过程:
首先,我们固定第一个字符a,求后面两个字符bc的排列
当两个字符bc排列求好之后,我们把第一个字符a和后面的b交换,得到bac,接着我们固定第一个字符b,求后面两个字符ac的排列
现在是把c放在第一个位置的时候了,但是记住前面我们已经把原先的第一个字符a和后面的b做了交换,为了保证这次c仍是和原先处在第一个位置的a交换,我们在拿c和第一个字符交换之前,先要把b和a交换回来。在交换b和a之后,再拿c和处于第一位置的a进行交换,得到cba。我们再次固定第一个字符c,求后面两个字符b、a的排列
既然我们已经知道怎么求三个字符的排列,那么固定第一个字符之后求后面两个字符的排列,就是典型的递归思路了。
function Permutation(str)
{
// write code here
if(str.length == 0)return '';
let str_arr = str.split('');
str_arr.sort();
let res = [];
for(let i = 0; i < str_arr.length; i++){
if(i > 0 && str_arr[i] === str_arr[i-1])continue;
let front = str_arr.slice(0,i);
let end = str_arr.slice(i+1);
PermutationHelp(res,str_arr[i],front.concat(end));
}
return res;
}
function PermutationHelp(res,temp, arr){
if (arr.length === 0) {
res.push(temp);
} else {
for(let i = 0; i < arr.length; i++){
if(i > 0 && arr[i] === arr[i-1])continue;
let front = arr.slice(0,i);
let end = arr.slice(i+1);
PermutationHelp(res,temp+arr[i],front.concat(end));
}
}
}
方法二:字典排列算法
/**
* 2、字典序排列算法
*
* 可参考解析: http://www.cnblogs.com/pmars/archive/2013/12/04/3458289.html (感谢作者)
*
* 一个全排列可看做一个字符串,字符串可有前缀、后缀。
* 生成给定全排列的下一个排列.所谓一个的下一个就是这一个与下一个之间没有其他的。
* 这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。
*
* [例]839647521是1--9的排列。1—9的排列最前面的是123456789,最后面的987654321,
* 从右向左扫描若都是增的,就到了987654321,也就没有下一个了。否则找出第一次出现下降的位置。
*
* 【例】 如何得到346987521的下一个
* 1,从尾部往前找第一个P(i-1) < P(i)的位置
* 3 4 6 <- 9 <- 8 <- 7 <- 5 <- 2 <- 1
* 最终找到6是第一个变小的数字,记录下6的位置i-1
*
* 2,从i位置往后找到最后一个大于6的数
* 3 4 6 -> 9 -> 8 -> 7 5 2 1
* 最终找到7的位置,记录位置为m
*
* 3,交换位置i-1和m的值
* 3 4 7 9 8 6 5 2 1
* 4,倒序i位置后的所有数据
* 3 4 7 1 2 5 6 8 9
* 则347125689为346987521的下一个排列
*
* @param str
* @return
*/
方法三:
function Permutation(str)
{
// write code here
//注意按字典序输出
var result=[];
if(str.length>0)
{
result.push(str);
var len=str.length;
var arr=str.split('');
while(true)
{
var a=len-1,b;
while(arr[a-1]>=arr[a]&&a>=1)
{
a--;
}
if(a==0){break;}
b=a;
while(b<len&&arr[b]>arr[a-1])
{
b++;
}
var temp;
temp=arr[a-1];
arr[a-1]=arr[b-1];
arr[b-1]=temp;
var arr1=arr.slice(a);
arr1.reverse();
var arr2=arr.slice(0,a);
arr=arr2.concat(arr1);
var s=arr.join('');
result.push(s);
}
}
return result;
}
【题13】用两个栈实现队列
题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
<分析>:
入队:将元素进栈A
出队:判断栈B是否为空,如果为空,则将栈A中所有元素pop,并push进栈B,栈B出栈;
如果不为空,栈B直接出栈。
var stackA = []
var stackB = []
function push(node)
{
stackA.push(node)
}
function pop()
{
if (stackB.length === 0) {
if (stackA.length === 0) {
return null
} else {
var len = stackA.length
for (var i = 0; i < len; i++) {
stackB.push(stackA.pop())
}
return stackB.pop()
}
} else {0
return stackB.pop()
}
}
拓展:用两个队列实现一个栈的功能
<分析>:
入栈:将元素进队列A
出栈:判断队列A中元素的个数是否为1,如果等于1,则出队列,否则将队列A中的元素 以此出队列并放入队列B,直到队列A中的元素留下一个,然后队列A出队列,再把队列B中的元素出队列以此放入队列A中。
【题】数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
方法一:
function MoreThanHalfNum_Solution(numbers)
{
var len = numbers.length
var arrLen = len/2, obj = {}
for(var i = 0; i < len; i++) {
if (obj[numbers[i]] === undefined) {
obj[numbers[i]] = 1
} else {
obj[numbers[i]]++
}
}
for (var j = 0; j < len; j++) {
if (obj[numbers[j]] > arrLen) {
return numbers[j]
}
}
return 0
}
方法二:关键点:数组中有一个数字出现的次数超过数组长度的一半,那么经过排序之后的数组,超过数组长度一半的数字一定在数组中间,因此判断之后,若存在的话一定是数组中间的数字。
function MoreThanHalfNum_Solution(numbers)
{
var len = Math.floor(numbers.length/2)
var count = 0
var middle = numbers[len]
numbers.sort((a, b) => {
return (a-b)
})
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] === middle) {
count++
}
}
if (count > len) {
return middle
} else {
return 0
}
}
【题14】连续子数组的最大和:
六大算法之动态规划:https://blog.youkuaiyun.com/zw6161080123/article/details/80639932
漫画:什么是动态规划:http://www.sohu.com/a/153858619_466939
HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
function FindGreatestSumOfSubArray(array)
{
//注意初始值 不能设为0 防止只有负数
var max = array[0]
var pre =array[0]
if (array.length < 0) {
return 0
}
//从1开始 因为0的情况在初始化时完成了
for (var i = 1; i < array.length; i++) {
// 当pre小于0时,就不要在继续往后累加了,因为这样只会越来越小。
if (pre < 0) pre = 0
max = Math.max(max, pre + array[i])
pre = pre + array[i]
}
return max
}
【题15】整数中1出现的次数(从1到n整数中1出现的次数)
求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
function NumberOf1Between1AndN_Solution(n)
{
if (n < 1) {
return 0
}
var num = 0, counts = 0
for (var i = 0; i <= n; i++) {
num = i
while (num > 0) {
if (num%10 === 1) {
counts++
}
num = Math.floor(num/10)
}
}
return counts
}
【题16】把数组排成最小的数
输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
function PrintMinNumber(numbers)
{
var res = ''
for (var i = 0; i < numbers.length; i++) {
for (var j = 0; j < numbers.length - i - 1; j++) {
var str1 = String(numbers[j]) + String(numbers[j+1])
var str2 = String(numbers[j+1]) + String(numbers[j])
if (Number(str1) > Number(str2)) {
var temp = numbers[j];
numbers[j] = numbers[j+1];
numbers[j+1] = temp;
}
}
res = String(numbers[numbers.length - i - 1]) + res
}
return res === '' ? '' : Number(res)
}
【题17】第一个只出现一次的字符
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).
function FirstNotRepeatingChar(str)
{
if (str.length === 0) {
return -1
}
var obj = {}
for (var i = 0; i < str.length; i++) {
if (obj[str[i]] === undefined) {
obj[str[i]] = 1
} else {
obj[str[i]]++
}
}
for (var j = 0; j < str.length; j++) {
if (obj[str[j]] === 1){
return j
}
}
}
【题18】和为S的两个数字
输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
对应每个测试案例,输出两个数,小的先输出。
function FindNumbersWithSum(array, sum)
{
var resultArray = []
for (var i = 0; i < array.length; i++) {
for (var j = 1; j < array.length; j++) {
if ((array[j] + array[i]) === sum) {
resultArray.push(array[i])
resultArray.push(array[j])
break;
}
}
if (resultArray.length) {
break
}
}
var aa = Array.from(new Set(resultArray))
return aa
}
【题19】和为S的连续正数序列
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
剑指offer课本解析:
function FindContinuousSequence(sum)
{
var small = 1
var big = 2
var middle = (1 + sum)/2
var cursum = small + big
var arr = []
while(small < middle) {
var aa = []
if (cursum == sum) {
for (var i = small; i <= big; i++) {
aa.push(i)
}
arr.push(aa)
}
while (cursum < sum && small < middle) {
big++
cursum += big
var aa = []
if (cursum == sum) {
for (var i = small; i <= big; i++) {
aa.push(i)
}
arr.push(aa)
}
}
cursum -=small
small++
}
return arr
}
【题20】扑克牌顺子
LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
function IsContinuous(numbers)
{
var len = numbers.length
var count = 0 // 记录大王小王即0的个数
var totalGap = 0
if (len == 0) {
return false
}
numbers.sort((a, b) => {
return a-b
})
for(var i = 0; i < len; i++) {
if (numbers[i] === 0) {
count++
continue
}
if (i < len - 1) {
var gap = numbers[i+1] - numbers[i] - 1
if (gap < 0) {
// 出现值相同的情况
return false
} else {
totalGap += gap
}
}
if (totalGap > count) {
return false
}
}
return true
}
【题21】正则表达式匹配
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
当模式中的第二个字符不是“*”时:
1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。
2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。
而当模式中的第二个字符是“*”时:
如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:
1、模式后移2字符,相当于x*被忽略;
2、字符串后移1字符,模式后移2字符;
3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
//s, pattern都是字符串
function match(s, pat) {
// write code here
var reg = new RegExp('^'+pattern +'$','g');
return reg.test(s);
}
//s, pattern都是字符串
function match(s, pat) {
/** 当pat为空时,若s为空则返回true否则返回false */
if (pat == "") return s == "";
/** 当pat长度为1时,直接判断是否匹配s,此时,pat一定不是‘*’ */
if (pat.length == 1) return s == pat || s.length == 1 && pat == ".";
/** 当pat长度大于1时,根据pat的第二个字符分情况讨论 */
if (pat[1] == "*") {
/** 当pat[1]为"*"时,先尝试直接跳过该任意次数字符 */
if (!match(s, pat.substr(2))) {
/** 跳过该字符无法匹配时,依次尝试让s的前1到s.length个字符与该字符匹配 */
for (let i = 0; i < s.length; i++) {
if (pat[0] != "." && pat[0] != s[i]) return false;
if (match(s.substr(i + 1), pat.substr(2))) return true;
}
return false;
} else return true;
} else {
/** pat[1] != '*' 则直接尝试匹配当前字符 */
if (pat[0] != "." && pat[0] != s[0]) return false;
return match(s.substr(1), pat.substr(1));
}
}
【题22】表示数值的字符串
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
//s字符串
function isNumeric(s)
{
return s.match(/[+-]?\d*(\.\d*)?([eE][+-]?\d+)?/g)[0] === s
}