前端面试题汇总及答案十二

 

132、函数式编程的定义

1)它是一种范式,创建仅依赖输入就可以完成自身逻辑的函数。

2)保证当参数一样,函数被多次调用时,返回相同的值(引用透明性)

3)函数不会改变任何外部环境的变量,这将产生可缓存、可测试的、合理的、可并发执行的代码库

 

132、纯函数的定义

对给定的输入返回相同输出的函数。

 

133、高阶函数

1)高阶函数通常用于抽象通用的问题,即定义抽象

2)参数为函数或者返回值为函数,则为高阶函数

1)、forEach(arr,fn)的实现----Array元素的遍历

function forEach(arr,fn){
	let i =0;
	let len = arr.length;
	for(;i<len;i++){
		fn(arr[i]);
	}
}

2)forEachObject(obj,fn)-----对对象的每一个属性遍历

function forEachObject(obj,fn){
	for(let prop in obj){
		if( obj.hasOwnProperty(prop) ){
			fn(prop,obj[prop]);
		}
	}
}

3)every(arr,fn)

const every = (arr,fn)=>{
	let ret=true;
	for( let item of arr ){
		ret = ret && fn(item);
	}
	return ret;
}

4)some(arr,fn)

const some = (arr,fn)=>{
	let ret=false;
	for( let item of arr ){
		ret = ret || fn(item);
	}
	return ret;
}

 

134、闭包

在javascript中,闭包是指有权访问另一个函数内部变量的函数。

闭包有3个可访问的作用域

1)在他自身内声明的变量

2)对全局变量的访问

3)对外部函数变量的访问

闭包可以记住上下文

1)tap函数----设计一个函数,该函数接受参数,并且返回值为函数,返回的函数也可以接受参数

调试参数

const tap = (val) => (fn)=>(typeof(fn)==='function'&&fn(value),console.log(val))

用途:遍历来自服务器的数组,数据错了,然后想调试数据

forEach([1,2,3],(a) => tap(a)( ()=>{console.log(a)} ) )

2)unary函数----将接受多个参数的函数转为只接受一个参数的函数

const unary = (fn) => fn.length === 1 ? fn : (arg) => fn(arg)

parseInt(parse,radix)

['1','2'].map(parseInt)//[1,NaN]
['1','2'].map( unary(parseInt) ) //[1,2]

 

3)once函数----只执行一次的函数,返回值为函数

const once = (fn)=>{
	let done = false;
	return  function(...arg){
		return done ? undefined : ((done=true),fn.apply(this,arg))
	}
}
let doPay = once( ()=>{console.log('payment is done')} )
doPay(); //'payment is done'
doPay(); //undefiend

 

功能函数和遍历函数分开

投影 函数-----把函数应用于一个值并创建一个新值的过程称为投影

1)map(arr,fn)----用一个新数组捕获结果并返回该数组

const map = (arr,fn)=>{
	let result = [];
	for( let item of arr ){
		result.push( fn(item) )
	}
	return result
}

//将每个元素平方
console.log(map([1,2,3],item => item*item)) //[1,4,9]

2)filter(arr,fn)-----过滤数组的内容,返回数组,成员是符合过滤条件的元素

const filter = (arr,fn) => {
	let result = [];
	for( let item of arr ){
		fn(item) ? result.push(item) : undefined
	}
	result;
}

3)concatAll(arr,fn)-----将嵌套的数组转为一维数组,只能测试下面的形式的嵌套数组

const concatAll = (arr,fn)=>{
	let result = [];
	for(let item of arr){
		result.push.apply(result,item);//使用apply将push的功能扩展为可以Push数组
	}
	return result
}

let arr = [[1,2],[3,4]]
console.log(concatAll(arr))

归约数组-----设置累加器并遍历数组(记住累加器的上一个值)以生成一个单一元素的过程

4)reduce(arr,fn,initVal)

const reduce = (arr,fn,initVal)=>{
	let acc;
	if( initVal != undefined ){
		acc = initVal;
	}else{
		acc = arr[0];
	}

	if( initVal===undefined ){
		for(let i =1;i<arr.length;i++){
			acc = fn(acc,arr[i]);
		}
	}else{
		for(let item of arr){
			acc= fn(acc,item);
		}
	}

	return [acc];
}


let arr = [1,2,3,4];
//数组元素相乘结果
console.log( reduce(arr,( acc,item )=>acc*item, 1) );
//数组元素相加
console.log( reduce(arr,( acc,item )=>acc+item, 0) );

5)zip(leftArr,rightArr,fn)-----对两个数组对应位置的元素进行处理,返回数组,数组元素是处理的结果

const zip = (leftArr,rightArr,fn)=>{
	let result=[];
	let len = Math.min(leftArr.length,rightArr.length);
	for(let i=0;i<len;i++){
		result.push(fn(leftArr[i],rightArr[i]));
	}
	return result;
}

//对两个数组对应位置元素相加,然后返回数组
let add = zip([1,2,3],[4,5,6],(val1,val2)=>val1+val2)
console.log(add);

 

135、柯里化与偏应用

柯里化的定义:柯里化就是把一个多参数的函数 转换为一个嵌套的一元函数的过程

curry(fn)=====返回值是一个函数或是一个函数的计算结果

const curry = (fn)=>{
	if( typeof(fn) !=='function' ){
		return Error('argument is error');
	}

	let len = fn.length;
	return function curried(...arg){
		if(arg.length<len){
			return (...arg1)=>curried.apply(null,arg.concat(arg1))
		}else{
			return fn.apply(null,arg);
		}
	}
}

let sum = curry((a,b,c)=>a+b+c);
console.log(sum(1)(2,3));

偏应用---允许开发者部分应用函数参数

例如:setTimeout(fn,number)------在程序中隐藏掉number

 

136、组合---把一个函数的输出作为另一个函数的输入,数据流方向从右到左

输出:函数

组合两个函数

const compose = (a,b)=>c=>a(b(c))

//计算一个字符串中单词数量
const splitToArr = str => str.split(',')
const count = arr => arr.length
const wordNUmber = compose(count,splitToArr)
console.log(wordNUmber('hh,jjjj')) 


组合多个函数----rest参数---接受多个参数 + reverse()----将数组元素倒序,数据流是从右到左 + reduce---将上次计算的结果作为下次计算的累加对象

注意:每个函数是一元函数

const reduce = (arr,fn,initVal)=>{
	let acc;
	if( initVal != undefined ){
		acc = initVal;
	}else{
		acc = arr[0];
	}

	if( initVal===undefined ){
		for(let i =1;i<arr.length;i++){
			acc = fn(acc,arr[i]);
		}
	}else{
		for(let item of arr){
			acc= fn(acc,item);
		}
	}

	return [acc];
}


const compose = (...arg)=>
	(val) => reduce(arg.reverse(),(acc,fn)=>fn(acc),val)


const splitToArr = str => str.split(',')
const count = arr => arr.length
const wordNUmber = compose(count,splitToArr)
console.log(wordNUmber('hh,jjjj'))

 

136、管道(序列)---- 把一个函数的输出作为另一个函数的输入,数据流方向从左到右(和组合很像)

 

 

 

136、判断1-400有多少个1

如:1-23有13个1

1)将1-400转换成字符串变量str;

2)正则表达式匹配字符串中的1:reg=/1/g

3)使用arr = str.match(reg);匹配到的结果都保存在数组arr中

4)通过arr.length获得1的个数

let reg = /1/g;
let str = '';
for(let i=1;i<=13;i++){
	str = str + i;
}
let arr = str.match(reg);
console.log(arr);

136、js中二进制和十进制的转换

十进制转换成二进制:num.toString(2)方法

二进制转换成十进制:parseInt(str,10)方法

parseFloat()会将小数点后面多余的0删掉

var num = 8;                                            //  定义一个十进制的整数
var str = num.toString(2);                         //  转换成二进制的字符串,2表示二进制  "1000"
var num1 = parseInt(str, 2);                 //  将二进制转换成十进制的整数,2也表示二进制    8
console.log(num1);

扩展:将给定数字转换成二进制字符串。如果字符串长度不足 8 位,则在前面补 0 到满8位。

var num = 8;
var str = num.toString(2);
var l = str.length;
var s1 = "00000000";                 //用于补齐,满8位

if(l < 8){

    var s2 = s1.slice(0,8-l);           //截取需要补齐的位数

    str = s2 + str;                       //在前面进行补齐

}

console.log(str);

 

136、输入字符串包含a-z和0-9,要求输出的字符串:显示字母后是数字,且都是升序排列

思路:

1)通过str.match分别匹配到输入字符串中的字母和数字,存放在数组arr1和arr2中

2)如果arr1有值,则进行快速排序,然后把结果拼接在字符串变量result中

3)如果arr2有值,则进行快速排序,然后把结果拼接在字符串变量result中

function quickSort(arr){
  let len = arr.length;
  if(len<2){
    return arr;
  }

  let mid = Math.floor(len/2);
  let midEle = arr.splice(mid,1);
  let left = [],
      right = [];
  for(let i=0;i<len-1;i++){
    if(midEle>arr[i]){
      left.push(arr[i]);
    }else{
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat(midEle,quickSort(right));
}

function sort(str){
  let reg1 = /[a-z]/g;
  let reg2 = /\d/g;
  let arr1 = str.match(reg1);
  let arr2 = str.match(reg2);
  let result = '';
  if(arr1){
    arr1 = quickSort(arr1);
    for(let val of arr1){
        result += val;
    }
  }
  if(arr2){
    arr2 = quickSort(arr2);
    for(let item of arr2){
        result += item;
    }
  }
  return result;
}



let  str = 'agh1zz9sd0z'    //adghszzz019
console.log(sort(str));

 

136、统计一个整数转成二进制之后含有1的个数

例: 
9 的二进制序列:0000 1001 
8 的二进制序列:0000 1000 
按位与后的序列:0000 1000 
此时count为1,n=8 
8 的二进制序列:0000 1000 
7 的二进制序列:0000 0111 
按位与后的序列:0000 0000 
此时count为2,即为9的二进制序列1的个数
// 二进制中1的个数,n = n&(n-1)
function NumberOfOneCount1( n)
{
    let count=0;
    while(n > 0) 
    {
        count++;
        n = n & (n-1);
    }
    return count;
}
console.log(NumberOfOneCount1(5));

 

136、输入两个整数,求两个整数二进制格式有多少个位不同

1)利用num.toString(2)转成二进制形式字符串str1,str2

2)如果str1与str2存在差别diff个,则cou=diff,否则cou=0

3)进行遍历,遍历次数为两个二进制字符串长度的最小值

4)每次遍历的时候进行比较:如果diff=0,则ind1=ind2=i;diff<0,则ind=i,ind2=i-diff;diff>0,ind1=i-diff,ind2=i;如果对应索引的字母相等则cou++

// 输入两个整数,求两个整数二进制格式有多少个位不同
let num1 = 188;
let num2 = 77;
let str1 = num1.toString(2);
let str2 = num2.toString(2);
let len1 = str1.length;
let len2 = str2.length;
let cou = 0;
let char1;
let char2;
let diff = len1-len2;
let diff2 = Math.abs(diff);
let ind1;
let ind2;
if(diff!==0){
	cou = diff2;
}
for(let i =0;i<Math.min(len1,len2);i++){
	if(diff===0){
		ind1=i;
		ind2=i;
	}else{
		
		if(diff>0){
			ind1=diff2+i;
			ind2=i;
		}else{
			ind1=i;
			ind2=diff2+i;
		}
	}
	
	char1 = parseInt(str1.charAt(ind1),10);
	char2 = parseInt(str2.charAt(ind2));
	if( char1!== char2){
		cou++;
	}
}
console.log(cou);

 

上面太复杂了,可以用先对num1和num2进行异或得num,然后统计num中二进制中1的个数

// 二进制中1的个数,num = num & (num-1);
function countOne(num1,num2)
{ 
    let num = num1 ^ num2;

    let reg = /1/g; 
    let arr = num.toString().match(reg); 
    return arr.length;
}
console.log(countOne(1,2));

 

136、两个数的最大公约数

//转辗相除法
用第一个数除以第二个数得到余数
如果余数为0,则第二个数就是最大公约数,返回
否则,用第二个数除以余数,回到步骤1(即将第二个数作为新的第一个数,将余数作为新的第二个数)
function gcd(m,n){
  if(n===0){
    return m;
  }else{
    return gcd(n,m%n);
  }
}
console.log(gcd(6,9));

136、判断是否是素数---除1之外,只能被1和自身整除,2也是素数

1)先判断是否为偶数,为偶数就一定不是素数

2)那就判断奇数,奇数从3开始,每次迭代加2

3)迭代次数为数M的开平方,开平方是M的最大因子,最大因子之后的数对判断该数是否是素数没有意义

function sushu(m){
  let i;
  if(m % 2 == 0)
      return false;

  for( i=3;i<=Math.sqrt(m);i+=2)
      if(m % i == 0)
          return false;
  return true;
}
console.log(sushu(9));

136、输入M,N,1<M<N<1000000,求区间[M,N]内的素数个数

function sushu(m){
  let i;
  if(m % 2 == 0)
      return false;

  for( i=3;i<=Math.sqrt(m);i+=2)
      if(m % i == 0)
          return false;
  return true;
}

function countSuShu(m,n){
  let count = 0;
  if(m==2){
    count++;
  }
  for(let i=m;i<=n;i++){
    if(sushu(i)){
      count++;
    }
  }
  return count;
}
console.log(countSuShu(3,10));

 

136、求连续区间的最大值

思路:用一个变量max保存连续区间的最大值,变量sum存储对每个元素的求和,在这里需要判断sum<0的时候,sum=0,同时sum和max比较,max<sum则max=-sum

// 最大连续和
function maxContinueSum(arr){
    let max = arr[0];
    let sum = 0;
    for(let val of arr){
        sum += val;
        if(sum<0){
            sum=0;
        }
        if(max<sum){
            max = sum;
        }
    }
    return max;
}
console.log(maxContinueSum([1,2,4]));

变型:连续区间的和最小

136、求连续区间的回文

// 找出区间的回文数
function huiwen(a){
    let b,c=0,d;
    d = a;
    while(d != 0){
        b = parseInt(d%10);  //b是d除以10的余数
        c = c*10 + b;        //c是c的10倍,加上d的余数
        d = parseInt(d/10);  //d是d除以10的商
    }
    if(c == a){  //c==a则为回文
        console.log(a);
    }
}
for(let i=100;i<124;i++){
    huiwen(i);     //101  111   121
}

137、给定一个未排序的数列,找出排序下的两个相邻值的最大差值,少于两个值时返回0

1)先排序

2)max保存最大差值,diff保存两数差值

3)每次迭代的时候,max<diff,则max=diff

例:[1,3,2,0,1,6,8],最大差值3

// 给定一个未排序的数列,找出排序下的两个相邻值得最大差值,少于两个值时返回0
// [1,3,2,0,1,6,8],最大差值3
function maxDiff(arr){
    let len = arr.length;
    let max = 0;
    let diff;
    if(len < 2){
        return max;
    }

    arr.sort((a,b) => a-b);
    for(let i=0;i<len-1;i++){
        diff = arr[i+1]-arr[i]
        if(max < diff ){
            max = diff;
        }
    }
    return max;
}

let arr = [1,3,2,0,1,6,8];
console.log(maxDiff(arr));

137、实现两个元素的交换

// 实现两个元素交换
function change(a,b){
   console.log('primitive: ' + 'a= ' + a + ', b=' + b)
   a ^= b;
   b ^= a;
   a ^= b;
   console.log('change: ' + 'a= ' + a + ', b=' + b)
}

change(2,3);

138、实现数字的倒序

// 实现数字倒序
// -12345倒序后-54321
function reverse(num){
    let temp = num;
    let r = 0;
    let t =temp;
    t = t>0?t:-t;
    for(;t;t = parseInt(t/10)){
        r = r*10 + parseInt(t%10);
    }
    return temp>0?r:-r;
}
console.log(reverse(-123));
// 数字倒序
function reverse(num){
    // 0-正数, 1-负数
    let flag = 0;
    if(num<0){
        flag=1;
    }
    num= parseInt(Math.abs(num).toString().split('').reverse().join(''),10);
    if(flag){
        num = parseInt('-' + num,10);
    }
    return num;
}
console.log(reverse(-102));

139、大富翁游戏,玩家根据骰子的点数决定走的步数,即骰子点数为1时可以走一步,点数为2时可以走两步,点数为n时可以走n步。求玩家走到第n步(n<=骰子最大点数且是方法的唯一入参)时,总共有多少种投骰子的方法

1    (1)      1种

2    (11) (2)  2种

3     (111) (12) (21) (3)  4种 

4     (1111) (112) (121) (212) (22)  (31) (13)  8种

。。。。。。。。f(n) = 1 +f(n-1)+f(n-2)+...+f(1)           

这是一个递归问题,想知道f(n) 必须查到栈底也就是f(1)所在,或者找出规律f(n) = 2^(n-1)

let n = parseInt(readline());
let result = 2**(n-1);
print(result);

 

140、给出一个非空的字符串,判断这个字符串是否是由它的一个子串进行多次首尾拼接构成的。输出最长的子串 
例如,”abcabcabc”满足条件,因为它是由”abc”首尾拼接而成的,而”abcab”则不满足条件,否则输出false

思想如下:从最长的二等分开始查找,用等分后的子字符串拼接成新的字符串B,与原字符串A进行比较,如果相等,返回这个字符串,如果不相等进行三等分以此类推,如果直至n等分(n=字符串A长度)都不能满足,输出false

// 判断字符串是否由淄川构成
// 首先对父串str二分,然后获取二分前面的子串str1,父串长/子串长=n次数,将子串str1复制n次得到str2
// 对比str===str2,若相等输出str1,flag=true,break;
// 若不等,在对父串3等分,。。。,直至1等分,还是没有符合条件的,证明父串不是由子串构成
let str = 'a';
let len = str.length;
let tmpLen = parseInt(len/2-1);
let flag = false;

for(let i=tmpLen;i>=0;i--){
	let str1 = str.slice(0,i+1);
	let len1 = str1.length;
	let str2='';
	//for(let j=0;j<len/len1;j++){
		//str2 += str1;
	//}
    str2 = str1.repeat(parseInt(len/len1))
	if(str == str2){
		console.log(str1);
		flag = true;
		break; 
	}

}
if(flag==false){
	console.log(false);
}

 

 

140、给出一个正整数n,请给出所有的包含n个'('和n个')'的字符串,使得'('和')'可以完全匹配

例如:

'(())()','()()()' 都是合法的;

'())()('是不合法的

function process( str,  res, nl,nr,  n) {
    // 若str中左括号的数量和右括号的数量都为n, 则将str添加到结果数组中, 并返回
    // 结束条件
    if (nl >= n && nr >= n) {
        res.push(str);
        return;
    }
    // 原则是先添加左括号
    if (nl < n) { // 左括号的数量不超过n
        str += '(';
        // 注意process每次都添加括号并删除括号, 返回时对传入的str没有做改变
        process(str, res, nl + 1, nr, n);  
        str = str.slice(0,str.length-1); // 删除push_back添加的左括号
    }
    // 若左括号的数量比右括号的多
    if (nl > nr) {
        str += ')'; // 补充一个右括号
        process(str, res, nl, nr + 1, n);
        str = str.slice(0,str.length-1);
    }
}

let str ='';
let n = parseInt(readline());
let res = [];
process(str,res,0,0,n);
str = res.join(',');
print(str);

 

 

140、给出一个字符串str,请给出所有的移除序列的方法

function count(str){
    let sum = 1;
    let len = str.length;
    let arr = [];
    let chara = '';
    for(let i=0;i<len;i++){
        chara = str.charAt(i)
        if( chara === '('){
            arr.push(chara);
        }else if( chara === ')' ){
           sum *= arr.length;
           arr.pop(); 
        }
        
    }
    return sum;
}
print(count(readline()));

141、给定一个字符串,看是否匹配,如()(){}[]---匹配输出yes,如()[}}---输出no

function isMatch(str){
  let stack = [],
      dict = {"]":"[", "}":"{", ")":"("},
      arr = ['[','{','('],
      char = '';
  for(char of str){
    if( arr.includes(char) ){
      stack.push(char);
    }else if( stack==[] || dict[char] != stack.slice(stack.length-1,stack.length)){
        return false
    }else if( dict[char] == stack.pop() ){
      continue;
    }else{
        return false;
    }
  }

  return (stack.length==0) ? true : false
}
console.log(isMatch('{}'));

 

 

 

150、给出一个整数n,将n分解为至少两个整数之和,使得这些整数的乘积最大化,输出能够获得的最大的乘积

思路:分解出来的3越多,乘积越大,当分解到剩4及以下时,可以看出此时再分解结果会更小,因此不予分解,直接相乘即可

function process(num){
    if(num=== 2){
        return 1;
    }else if( num ===3 ){
        return 2;
    }else if( num ===4 ){
        return 4;
    }
    let res = 1;
    while(num > 4){
        res *= 3;
        num -=3;
    }
    if(num !== 0){
        return res*num;
    }else{
        return res;
    }
    
}
console.log(process(12));

 

151、从非负整数序列 0, 1, 2, ..., n中给出包含其中n个数的子序列,请找出未出现在该子序列中的那个数

输入为n+1个非负整数,用空格分开。
其中:首个数字为非负整数序列的最大值n,后面n个数字为子序列中包含的数字
// 将所有的数字都遍历一遍,字符不在字符串里面就输出
let str = readline();
let arr = str.split(' ');
let m = parseInt(arr[0]);
for( let i=0;i<=m;i++){
    if( !str.includes(i+'') ){
        print(i);
    }
}

152、小招喵喜欢在数轴上跑来跑去,假设它现在站在点n处,它只会3种走法,分别是:
1.数轴上向前走一步,即n=n+1 
2.数轴上向后走一步,即n=n-1 
3.数轴上使劲跳跃到当前点的两倍,即n=2*n
现在小招喵在原点,即n=0,它想去点x处,快帮小招喵算算最快的走法需要多少步?

注意:起点为0,输入的数字为正和为负的步数是一样的,所以当x<0的时候,只需要将x变为正数即可,后面只考虑正数的算法

 

思路:

一个动态规划问题,小猫有两种跳跃方式:1. 一次走一步,2.一次走2倍与当前位置的步数。

dp方程:

dp[i-1] = min(dp[i-1], dp[i/2])+1 (i % 2 == 0)

dp[i-1] = min(dp[i-1], dp[(i+1)/2+1] + 1 (i % 2 != 0)

当i为偶数时,对于跳跃方式2来说,可以从前一个位置直接跳过来,即dp[i/2]。

当i为奇数时,对于跳跃方式2来说,需要在前一个位置跳过来需要两步,先方式2后方式1.

function process(x){
    if(x<0){
        x = -x;
    }
    if(x<2){
        return x;
    }
    let dp = [0,1];
    for(let i = 2;i<=x;i++){
        if(i%2==0){
            dp[i] = Math.min(dp[i-1],dp[i/2])+1;
        }else{
            dp[i] = Math.min(dp[i-1],dp[(i+1)/2]+1)+1;
        }
    }
    return dp[x];
}
print(process(parseInt(readline())));

 

153、给定一组非负整数组成的数组h,代表一组柱状图的高度,其中每个柱子的宽度都为1。 在这组柱状图中找到能组成的最大矩形的面积(如图所示)。 入参h为一个整型数组,代表每个柱子的高度,返回面积的值

// 分治法:最大矩形面积只可能有三种情况:
// 1. 取决于高度最小的柱子,此时面积等于高度乘总长度;
// 2. 最大面积出现在高度最小的柱子左边;
// 3. 最大面积出现在高度最小的柱子右边;
function largestArea(x){
    let len = x.length;
    let minNumIndex = x.indexOf((Math.min.apply(null,x)));

    let val1 = x[minNumIndex] * len;
    let val2,
        val3;

    if( minNumIndex != 0 ){
        val2 = largestArea(x.slice(0,minNumIndex+1));
    }else{
        val2 = 0;
    }

    if( minNumIndex !=len-1 ){
        val3 = largestArea(x.slice(minNumIndex+1));
    }else{
        val3 = 0;
    }
    return Math.max.call(null,val1,val2,val3)
}

let n = parseInt(readline());
let arr = readline().split(' ');
arr.forEach(function(val,key){
       arr[key] = parseInt(val);
});
print(largestArea(arr));

154、f(x)表示把x这个数用十进制写出后各个数位上的数字之和。如f(123)=1+2+3=6。 g(x)表示把x这个数用二进制写出后各个数位上的数字之和。如123的二进制表示为1111011,那么,g(123)=1+1+1+1+0+1+1=6。 小明同学发现对于一些正整数x满足f(x)=g(x),他把这种数称为幸运数,现在他想知道,大于0且小于等于n的幸运数有多少个? 

每组数据输入一个数n(n<=100000)
每组数据输出一行,小于等于n的幸运数个数
let n = parseInt(readline());
let result = 0;
let intNum;
for(let num=1;num<=n;num++){
    if( count10Sum(num) ===  count2sum(num) ){
       result++; 
    }   
}
print(result);

function count10Sum(num){
    let arr = num.toString().split('');
    let sum = 0;
    arr.forEach((item)=>{
        sum += parseInt(item);        
    })
    return sum;
}

function count2sum(num){
    let str = num.toString(2);
    let len = (str.match(/1/g)).length;
    return len ? len : 0;
}

 

 

156、给你两个集合,要求{A} + {B}。 注:同一个集合中不会有两个相同的元素

每组输入数据分为三行,第一行有两个数字n,m(0 ≤ n,m ≤ 10000),分别表示集合A和集合B的元素个数。后两行分别表示集合A和集合B。每个元素为不超过int范围的整数,每个元素之间有个空格隔开
针对每组数据输出一行数据,表示合并后的集合,要求从小到大输出,每个元素之间有一个空格隔开,行末无空格
let nm = readline().split(' ');
let n = parseInt(nm[0]);
let m = parseInt(nm[1]);
let A = readline().split(' ');
let B = readline().split(' ');
A.forEach((item,key)=>{
   A[key] = parseInt(item);   
});
B.forEach((item,key)=>{
   B[key] = parseInt(item); 
});
let arr = A.concat(B);
let str ='';
arr =  [...new Set(arr)];
arr.sort((a,b)=>a-b);
arr.forEach((item)=>{
    str += item + ' ';        
});

str = str.replace(/\s$/,'');
print(str);

 

 

尽管是一个CS专业的学生,小B的数学基础很好并对数值计算有着特别的兴趣,喜欢用计算机程序来解决数学问题,现在,她正在玩一个数值变换的游戏。她发现计算机中经常用不同的进制表示一个数,如十进制数123表达为16进制时只包含两位数7、11(B),用八进制表示为三位数1、7、3,按不同进制表达时,各个位数的和也不同,如上述例子中十六进制和八进制中各位数的和分别是18和11,。 小B感兴趣的是,一个数A如果按2到A-1进制表达时,各个位数之和的均值是多少?她希望你能帮她解决这个问题? 所有的计算均基于十进制进行,结果也用十进制表示为不可约简的分数形式

输入中有多组测试数据,每组测试数据为一个整数A(1 ≤ A ≤ 5000)
对每组测试数据,在单独的行中以X/Y的形式输出结果

输入:

5
3

输出:

7/3
2/1
let arr = readline().split(' ');
let result = [];   //存放结果

arr.forEach((val,key)=>{
    arr[key] = parseInt(val);    
});

arr.forEach((val)=>{
   result.push(count(val));            
});

result.forEach((val)=>{
   console.log(val);            
})
function count(num){
   let i =2;
    let sum = 0;
    let tmp;
    for(;i<=num-1;i++){ //cong 2-num-1进制
        let bus ;
        let rem;
        let tmpNum = num;
        do{
          bus = Math.floor(tmpNum/i);
          rem = Math.floor(tmpNum%i);  
            if(rem!== 0){
              sum += rem;  
            }
            tmpNum = bus;
        }while(tmpNum);
    }
    let mul = gcd(sum,num-2);
    return (sum/mul) + '/' + ((num-2)/mul);  //最简形式
}

function gcd(m,n){  //求最大公约数,辗转相除法
    if(n===0){
       return m; 
    }else{
        return gcd(n,m%n);
    }
}

 

数字num转为n进制的时候sum存转化为n进制后各个位上的值,利用商bus=parseInt(num/n),余数rem=parseInt(num%n),若rem!=0,则sum += rem;num=bus.

若果num!=0,则重复上面步骤。

sum是分子和,分母就是表示进制数的种类num-2.由于要求最简形式,所以还得求出最大公约数

 

最小公倍数 = n*m /最大公约数

匹配标点符号和空格:reg = /\s|\pP/; //空格或者标点符号

 

157、实现大数相加

// 大数相加,转化为字符串相加,从低向高做加法运算,既不会溢出,也不会损失精度
function sumStrings(a,b){
    var res='', c=0;   //---res存放结果,c保留进位
    a = String(a).split('');
    b = String(b).split('');
    while (a.length || b.length || c){
        // ~~a 转换成数字类型   ~~true = 1   ~~!undefined = 1
        // ~~undefined = 0
        // array pop()没有元素弹出则返回undefined
        c += ~~a.pop() + ~~b.pop();  //将两个数转化为数字类型,进行相加
        res = c % 10 + res;  //两数相加的个位值:c % 10
        c = c>9;    
    }
    return res.replace(/^0+/,'');    //将前缀0去掉
}

console.log(sumStrings('123','42'));

 

156、给定两个字符串,求最长公共子序列

// 找A、B序列的最长公共序列
//c[][]记录最长公共序列长度, b[][]记录最长公共序列长度的来源用1,2,3标志
// s1[i] == s2[j-1],i=0,...len1-1,j=1,...,len2,c[i][j] = c[i-1][j-1],b[i][j]=1
// s1[i]不等于s2[j-1],如果c[i][j-1]>=c[i-1][j],c[i][j] = c[i][j-1],b[i][j]=2
// 如果c[i][j-1]< c[i-1][j],c[i][j] = c[i-1][j],b[i][j]=3
// 记录最长公共序列长度=c[len1][len2]

// 最优结果则是倒序,b[i][j]=1,则s1[i-1]=s2[j-1],输出s1[i-1]
// 接着在看b[i-1][j-1]直到i=0或者j=0才结束,递归

// 实现c[][]   b[][]
function LCSL(str1,str2,c,b){
    let len1 = str1.length,
        len2 = str2.length,
        i = 0,j,
        tmp = [];

    // 初始化c[][] len1+1行   len2+1列
    for(;i<=len2;i++){  //初始化第一行全为0
        tmp.push(0);
    }
    c.push(tmp);
    b.push(tmp);
    for(i=0;i<len1;i++){
        c.push([0]);  //第一列全为0
        b.push([0]);
    }

    for( i=1;i<=len1;i++ ){//控制str1序列
        for(j=1;j<=len2;j++){//控制str2序列
            if( str1[i-1] == str2[j-1] ){
                //如果当前字符相同,则公共子序列的长度为该字符前的最长公共子序列+1
                c[i][j] = c[i-1][j-1]+1;
                b[i][j] = 1;
            }else{
                if( c[i][j-1] >= c[i-1][j] ){
                    c[i][j] = c[i][j-1];
                    b[i][j] = 2;
                }else{
                    c[i][j] = c[i-1][j];
                    b[i][j] = 3;
                }
            }
        }
    }
}

// 求解最优解
function show(str1,b,i,j){
    // 递归结束条件
    if( i==0 || j == 0 ){
        return; 
    }

    if( b[i][j] == 1){
        //递归
        show(str1,b,i-1,j-1);
        // 输出
        console.log(str1.charAt(i-1));
    }else if( b[i][j] == 2 ){
        //递归
        show(str1,b,i,j-1);
    }else{
        //递归
        show(str1,b,i-1,j);
    }
}

let str1 = 'ABCADAB',
    str2 = 'BACDBA',
    len1 = str1.length,
    len2 = str2.length,
    c=[],
    b=[];

LCSL(str1,str2,c,b)
console.log(c,b);
console.log('最长序列长度:' + c[len1][len2]);
console.log(show(str1,b,len1,len2)); //递归构造最长公共序列最优解

156、石头合并问题---路边玩法(直线)和操场玩法(圆)

// a[i]第i堆石子的数量
// sum[i]前i对石子的重量(a1,...,ai)
// min[i][j]  max[i][j]记录第i堆到第j堆(ai,...,aj)的 重量=sum[j]-sum[i-1]
// 初始化,min[i][i]=0,max[i][i]=0,sum[0]=0,计算sum[i],i=1,...n
// 按照公式,循环
// 计算2堆合并的,3对合并,...,n堆合并最小(大)花费
// 最优解:min[1][n]   max[1][n]
let min = [],
    max = [],
    tmp1 = [],  //用于初始化min[i][i],max[i][i]
    tmp2 = [],
    sum = [],  // sum[i]前i对石子的重量(a1,...,ai)
    min_circular,
    max_circular;
let n = 6; //对数
let a = [0,5,8,6,9,2,3];//每堆的重量
// straight(a,n); //直线
// console.log(min[1][n],max[1][n]);

circular(a,n);  //环线
console.log(min_circular,max_circular);

function straight(a,n){
    // 初始化 min[i][i]=0,max[i][i]=0
    for(let i=0;i<=n;i++){
        tmp1 = [];
        tmp2 = [];
        tmp1[i] = 0;
        tmp2[i] = 0; 
        min.push(tmp1);   //这里要注意,不能讲同一个数组作为min  max的元素,这样的话就会共享内存
        max.push(tmp2)
    }

    // 前0堆石子重量为0
    sum[0] = 0;

    // 计算前i堆石子的重量
    for( let i=1;i<=n;i++ ){
        sum[i] = sum[i-1] + a[i];
    }

    // 按照公式
    for( let v=2;v<=n;v++ ){ //枚举合并的堆数的规模
        for( let i=1;i<=n-v+1;i++ ){ //枚举起始点i
            let j = i+ v-1; //枚举j点
            min[i][j] = Infinity;  //初始化最大值
            max[i][j] = -1;  //初始化为-1
            let w = sum[j] - sum[i-1];  //记录i...j之间的石子数之和
            // 枚举中间分割点:k>=i,k<j
            for( let k=i;k<j;k++ ){
                min[i][j] = Math.min( min[i][j], min[i][k] + min[k+1][j] + w );
                max[i][j] = Math.max( max[i][j], max[i][k] + max[k+1][j] + w );
            }

        }
    }
}

function circular( a,n ){
    for( let i =1;i<=n-1;i++ ){ //2*n-1
        a[n+i] = a[i];
    }

    n = 2*n-1;
    straight(a,n);
    n=(n+1)/2;
    min_circular = min[1][n];
    max_circular = max[1][n];
    for( let i=2;i<=n;i++ ){
        if( min[i][n+i-1] < min_circular ){
            min_circular = min[i][n+i-1];
        }
        if( max[i][n+i-1] > max_circular ){
            max_circular = max[i][n+i-1];
        }
    }
}

 

156、最大价值----可拆分-----贪心算法

毛驴可载重为一个固定值m,洞中有宝物n件,宝物的重量和价值分别为w   v,宝物可拆分,如何挑选可得到最大价值的宝物(按照性价比由大到小挑选)

// 求最大宝物价值,可拆分,选择性价比的原则
let n = 6,  //宝物数量
    w = 19;   //毛驴载重量
// 6行,每行包括宝物的重量和价值,后面经过处理在吗 每行的末尾加上性价比
let arr = [];
for( let i=0;i<n;i++ ){
    let tmp = [];  //每次循环都重新声明,所以不会共享内存
    tmp = readline().split(' ');
    tmp.forEach( (val,key)=>tmp[key]= ~~val ); //~~转为整数
    tmp.push( parseFloat( tmp[1]/tmp[0] ) );  //性价比
    arr.push(tmp);
}

arr.sort( (a,b) => b[2]-a[2] ); //按照性价比又高到低排序

let sum = 0;  //存放价值量
for( let i=0;i<n;i++ ){//对排序好的进行累加
    if( arr[i][0] < w ){ //宝物重量小于毛驴的剩下载重量,则进行处理
        w -= arr[i][0]; //毛驴剩下载重量
        sum += arr[i][1] //累加可以载的宝物的价值
    }else{
        // 宝物重量>毛驴剩下载量
        sum += w * arr[i][2];
        break;
    }
}

console.log(sum);

 

156、最大价值----不可拆分-----动态规划   0-1背包问题

分配购物车容量m,有n个物品,每个物品重量、价值分别为w   v,物品不可拆分,在不超重的情况下如何挑选物品使总价值最大,挑选的物品具体是什么,最大价值?

// 不是最优方法
let n = 5,  //物品个数
    m = 10; //购物车容量

// let w =readline().split(' '); //每个物品的重量
//     w = w.forEach( (val,key) => w[key] = ~~val );
let w=[1,2,3,4,5];
w.unshift(0);//使第一件物品对应下标1

// let v =readline().split(' '); //每个物品的价值
//     v = v.forEach( (val,key) => v[key] = ~~val );
let v = [6,3,5,4,6];
v.unshift(0);//使第一件物品价值对应下标1


let c = [];//第i件物品放入载量j的总价值c[i][j]
let tmp = [];
for( let i=0;i<=m;i++ ){
    tmp.push(0);
}
c.push(tmp);
// 初始化第0行,0列为0
for( let i=1;i<=n;i++ ){
    tmp = [];
    tmp[0] = 0;
    c.push(tmp);
}

for( let i=1;i<=n;i++ ){  //计算c[i][j]
    for( let j=1;j<=m;j++ ){
        if( w[i] > j ){ //当物品重量大于购物车容量不放入
            c[i][j] = c[i-1][j];
        }else{
            // 否则比较此物品放和不放是否使得购物车内总价值最大
            c[i][j] = Math.max( c[i-1][j], c[i-1][j-w[i]] + v[i] );
        }
    }
}

console.log('maxval: '+ c[n][m]);

// 逆向构造最优解
let h = w;  //购物车容量
let x =[0]; //1表示放进去,0-不放
for( let i=n;i>0;i--  ){
    if( c[i][h] > c[i-1][h] ){//说明i物品放进容量j
        x.push(1);
        h -= w[i]; //购物车剩余容量
    }else{
        x.push(0);
    }
}
console.log('装入购物车的物品为:');
x.forEach( (val,key)=>{
    if( val ===1  ){
        console.log(key);
    }
});

 

优化算法:

 

157、加工顺序,时间最短

n个零件,每个零件先由机器1处理后由机器2处理,时间t1i   t2i,

贝尔曼规则:

(1)第一台机器上加工时间越短越先加工

(2)第二台机器上加工时间越长越先加工

(3)第一个机器上加工时间小于第二个加工时间先加工

(4)第一个机器上加工时间小大于等于第二个加工时间后加工

 

算法:

(1)将零件分成两个集合N1={ i| t1i <  t2i }第一个机器上加工时间小于第二个机器上加工时间;N2={ i| t1i >=  t2i }第一个机器上加工时间大于等于第二个机器上加工时间;

(2)N1按照非递减的顺序排序(t1i时间小的排在前面)(排序后:1 2 2 3 4 4)   ;N2按照非递增排序(t2i时间大的排在前面)(排序后:6 6 5 4 3)

(3)拼接N1N2就是加工顺序

// 
let arr = [];
let n = 7;  //加工零件个数
// let tmp = [];
let tmp = [[3,7],[8,2],[10,6],[12,18],[6,3],[9,10],[15,4]];

for( let i=0;i<n;i++ ){
    // let tmp = [];
    let obj = {};  //每次都会重新定义,所以不会共享内存
    // tmp = readline().split(' ');

    obj.id = i;
    // obj.x = ~~tmp[0];
    obj.x = ~~tmp[i][0];  //这样定义,也是这样obj.x才能访问到
    obj.y = ~~tmp[i][1];
    arr.push(obj);
}

// 分集合N1(t1i < t2i)    N2(t1i >= t2i)
let N1 = [],
    N2 = [],
    item;

for( let i=0;i<n;i++ ){
    item = arr[i];
    if( item.x < item.y ){
        N1.push(item);
    }else{
        N2.push(item);
    }
}

// N1非递减,N2非递增
N1.sort( (a,b) => a.x - b.x );
N2.sort( (a,b) => b.y - a.y );

arr = N1.concat(N2); //结果
console.log("最优加工顺序:");
arr.forEach( val=>console.log(val.id) );

// 加工时间
let f1 =0,
    f2 = 0;
for( let i=0;i<n;i++ ){
    f1 += arr[i].x;
    f2 = Math.max(f1,f2) + arr[i].y;
}
console.log(f2);

 

或略掉小数点后多余的0

console.log( parseFloat(123.00000) ) //123
console.log( parseFloat(123.010000) ) //123.01
console.log( parseFloat(123) )//123

 

小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4..., 每隔m个符号翻转一次, 最初符号为'-';。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少

//一个数列共有n/2m组,每一组的和为m^2
//所以,前n项和为:(n/2m)*(m^2)=m*n/2
let arr  = readline().split(' ');
let n = ~~arr[0];
let m = ~~arr[1];
let com = ~~(n/2/m);
let sum = (m ** 2) * com;
print(sum);

牛牛和羊羊正在玩一个纸牌游戏。这个游戏一共有n张纸牌, 第i张纸牌上写着数字ai。
牛牛和羊羊轮流抽牌, 牛牛先抽, 每次抽牌他们可以从纸牌堆中任意选择一张抽出, 直到纸牌被抽完。
他们的得分等于他们抽到的纸牌数字总和。
现在假设牛牛和羊羊都采用最优策略, 请你计算出游戏结束后牛牛得分减去羊羊得分等于多少

//最优策略---每次每个人拿的数都是剩下里面最大的数
//对数据按照非升序排序
let n = ~~readline();
let arr = readline().split(' ');
arr.forEach((val,key)=>arr[key]= ~~val);
arr.sort((a,b)=>b-a);
let sum1 = 0, //牛牛
    sum2 = 0; //洋洋
for(  let i=0;i<n;i++ ){
    if( Math.floor((i%2))== 0 ){
       sum1 += arr[i]; 
    }else{
       sum2 += arr[i];
    } 
}
print(sum1-sum2);

 

let n = ~~readline();//天数
let m = ~~readline();//块数
function sum(a){
    //a是第一天吃的块数
    //这里是求第一天吃a块,n天吃的块数
    let count = 0;
    for(let i=0;i<n;i++){
        count += a;
        a = Math.ceil(a/2);
    }
    return count;
}
let low = 1;
let high = m;
let mid;
let first;
while(low<high){
    mid = Math.ceil((low+high)/2);
    first = sum(mid);
    if( first == m  ){
        break;
    }else if( first < m ){
        low += 1;
    }else{
        hight--;
    }
}
print(first);

 

判断数组B是否是数组A的子集

针对数组是否是有序和无序进行不同的处理

// 无序、有重复
// 无序,那么对B的每一个元素遍历,每次遍历一个元素的时候就在A中找,如果A中没有返回false,如果有则
// 利用indexOf()找出该元素在A数组中的位置,然后用splice()将该元素删除
// function subset(A,B){
// 	let len1 = A.length,
// 		len2 = B.length, 	
//  		tmp;
// 	for(let i=0, len=B.length; i<len; i++){
// 		tmp = A.indexOf(B[i]);
// 		if( tmp === -1){
// 		   return false;
// 		}else{
// 		  A.splice( A.indexOf(B[i]), 1);
// 		}
// 	}
// 	return true;
// }

// let A = [3,2,1,4,4];
// let B = [4,4];
// console.log( subset(A,B) );


// 对于有序的话,对B遍历,每次都判断在B中的当前元素在A中是否存在,如果存在就将标志A中的元素的下标加1,
// 下次在A中查找元素的话,就会从该下标开始
function subset(A,B){
	let len1 = A.length,
		len2 = B.length, 	
 		index = 0;
 	// 判断边界条件
 	if( len1 < len2 ){
 		return false;
 	}else if( B[0] > A[len1-1]  || B[len2-1] > A[len1-1] ){
 		return false;
 	}

 	// 对B遍历
	for(let i=0; i<len2; i++){
		index = A.indexOf(B[i],index);
		if( index === -1){
		   return false;
		}else{
			index++;
		}
	}
	return true;
}

let A = [3,4,4];
let B = [4,4,8];
console.log( subset(A,B) );

200、在移动端实现特殊链接---利用H5的js提供的接口

1)打电话

//1、常用方式
<a href="tel:10086">10086</a>
//2、使用wtai协议进行拨打电话
<a href="wtai://wp/mc;10086">10086</a>

2)发短信

//格式
sms:<phone-number>[,<phone-number>]*[?body=<message_body>]
//例子
<a href="sms:10086">给 10086 发短信</a><br />
<a href="sms:10086?body=cxye">给 10086 发送内容为"cxye"的短信</a><br />
<a href="sms:10086,10010?body=cxye">给 10086 和 10010 发送内容为"cxye"的短信</a>

3)发邮件,使用mailto

<a href="mailto:test1@163.com">mail</a>
<a href="mailto:test1@163.com,test2@126.com">mail</a>
<a href="mailto:test1@163.com?subject=Testing">mail</a>
<a href="mailto:test1@163.com?subject=Testing mailto&cc=test3@126.com">mail</a>

4)地图定位GPS

//格式
<a href="geopoint:[经度],[纬度]">我的位置</a>
//例子
<a href="geopoint:108.954823,34.275891">我的位置</a>

201、输出结果

1、
function switchCase(value){
    switch(value){
        case '0':console.log('case 0');
        case '1':console.log('case 1');break;
        case undefined:console.log('undefined');break;
        default:console.log('default');
}
}
  
// 写出下列输出结果
switchCase(0);          //default-----不会发生转换
switchCase('0');       //case 0   case 1-----因为case '0'后面没有break,所以继续执行
switchCase();          //undefined-----没有参数,默认为undefined


2、

用ES6解构的方式,将下面代码中的obj.name赋值给n,obj.age赋值给a
let obj = {name:’韩梅梅’, age:’20’};
let n, a
实现:
let {name: n, age: a} = obj;


3、
var s = {
  s: 'student',
  getS: function(){
    console.log(this.s);
  }
};
var t = {
  s: 'teaher'
};

var getS = s.getS; 
var getS1 = getS.bind(s);

// 写出以下输出结果
s.getS();    //student
s.getS.apply(t);    //teaher
getS();   //{s: "student", getS: ƒ},this=window,window.s刚好是s对象
getS1.call(t);  //student

202、 用js实现一个随机打乱数组顺序的函数,要求可以设定数组种任意1个元素的位置不变,其他位置的元素位置随机变化

//当产生的随机数和传进来的索引不一样的时候,才会返回随机数
function randNum(low,high,unChangeIndex){
  let tmp;
  do{
    tmp = Math.round( Math.random()*(high-low) + low );
  }while(tmp == unChangeIndex);
  return tmp;
}

function mixSort(arr,ele){
  let len = arr.length,
      index = arr.indexOf(ele),
      tmpIndex,
      tmpEle;
  //对数组的每一个元素(除了传进来位置不变的元素外)遍历,实现混排
  for(let i=0;i<len;i++){
    if( i!== index ){
      tmpIndex = randNum( 0,i ,index);
      tmpEle = arr[tmpIndex];
      arr[tmpIndex] = arr[i];
      arr[i] = tmpEle
    }
  }
}

let arr = [1,2,3,4];
mixSort(arr,3)
console.log(arr);

 

202、 比较两个版本号的 大小

function compare(str1,str2){
  let arr1 = str1.split('.'),
      arr2 = str2.split('.'),
      len1 = arr1.length,
      len2 = arr2.length;

  //将两个数组的长度补到一样长
  if( len1 < len2 ){
    for( let i=0;i<len2-len1;i++ ){
      arr1.push('0');
    }
    len1 = len2;
  }else if( len1 > len2 ){
      arr2.push('0');
      len2 = len1;
  }

  for( let i=0;i<len1;i++ ){//str1<str2,-1;  str1==str2,0;   str1>str2,1 
    if( arr1[i] < arr2[i]){
      return -1;
    }else if( arr1[i] > arr2[i]  ){
      return 1;
    }else{
      continue;
    }
  }
  return 0;
}

let str1 = '1.0.2';
let str2 = '2.0';
console.log( compare(str1,str2) );

203、 用css3画圆,椭圆,三角形

1)三角形原理:通过border来设置,理解盒子模型,就可以设置任意三角形

<div class='div1'></div>
.div1{
     width: 100;
     height: 100;
     border-left: 100px solid red;
     border-right: 100px solid black;
     border-bottom: 100px solid green;
     border-top:100px solid yellow;
}

效果:整个盒子的宽度为width+border-left-width+ border-rigth-width=100+100+100,heigth同理

如果将上面的height:0其他代码不变,显示效果如下,

heigth=0,width=0,其他不变,显示如下

如果,不设置border-bottom,默认为0,显示效果如下

如果把border-left   border-right的color设为transparent,显示:

画直角三角形

.div1{
   width: 0;
   height: 0;
   border-left: 100px solid red;
   border-top:100px solid transparent;
}

2)画梯形和画三角形的原理一样,通过设置border在结合border-color为transparent

如果设置的是上(下)梯形,那么width不能为0,如果设置的是左右梯形,那么height不能为0

 .div1{
     width: 100px;
     height: 100px;
     border-left: 100px solid transparent;
     border-right: 100px solid transparent;
     border-bottom: 100px solid transparent;
     border-top:100px solid yellow;
}

效果如下

 

 

3)圆形原理---利用width=height(先画方形),在设置border-radius:50%

画一个圆

<div class='div1'></div>

.div1{
   width: 100px;
   height: 100px;
   border-radius: 50%;
   background-color:red;
}

效果:

画同心圆:div里面内嵌子div,一级套一级,然后利用垂直水平居中技术实现同心圆

<div class='div1'>
  <div class='div2'></div>
</div>

.div1{
   position:relative; 
   width: 100px;
   height: 100px;
   border-radius:50%;
   background-color:red;
   text-align: center;
}
.div2{
    position:absolute;
    top:0;
    right:0;
    bottom:0;
    left:0;
    margin:auto;
    width: 50px;
    height: 50px;
    border-radius:50%;
    background-color:green;
}

<div class='div1'>
  <div class='div2'>
    <div class="div3"></div>
  </div>
</div>



.div1{
     position:relative; 
     width: 100px;
     height: 100px;
     border-radius:50%;
     background-color:red;
}
.div2{
      position:absolute;
      top:0;
      right:0;
      bottom:0;
      left:0;
      margin:auto;
      width: 50px;
      height: 50px;
      border-radius:50%;
      background-color:green;
}
.div3{
      position:absolute;
      top:0;
      right:0;
      bottom:0;
      left:0;
      margin:auto;
      width: 30px;
      height: 30px;
      border-radius:50%;
      background-color:white;
}

 

4)画椭圆,先画矩形,在设置border-radius:50%

.div1{
   position:relative; 
   width: 200px;
   height: 100px;
   border-radius:50%;
   background-color:red;
}

 

203、 js中的按位非(~)的本质:操作数的负值减1----和c有区别

//~按位非:操作数的负值减1
console.log( ~(2+'3') );   //-24
console.log( ~undefined ); //-1
console.log(~NaN); //-1

输出结果

let y = 0.3-0.2;
let z = 7;
let obj = {a:10};


let change = function(obj){
  if(obj instanceof Object){
      if(y===0.1){
        obj.a = 8;
      }else{
        obj = { t:'mumble' };
      }
  }else{
    obj=9;
  }
}
change(obj);
change(z);
console.log('y  '+y);     //0.09999999999999998
console.log('z  '+z);      // 7
console.log('obj  '+obj); // { t:'mumble' }

204、 js中的eval(str)函数和with()函数

严格模式下不允许使用with语句

with 语句的作用是将代码的作用域设置到一个特定的对象中;目的暂时改变作用域,简化多次编写同一个对象的工作

调用with(obj)的时候,函数会创建一个新的活动对象,将该活动对象推到作用域的最前端,该对象就是with的对象。这就意味着所有的局部变量都处于第二个作用域链对象中去了,这也就是为什么要避免使用with的原因

var a = 123;
var b = {a : 321};
with(b){
console.log(a); // 321
}
var a = 123;
var b = {}; 这里去掉b中的a属性
with(b){
console.log(a); // 123
} //从作用域链来分析

 

eval(str)

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码

 var obj = eval("({age:26, name:'rose'})");//返回一个对象
 console.log(obj.age);

 

204、 伪元素(::)和伪类(:)

https://www.cnblogs.com/Yfling/p/7259949.html     详细介绍

伪类的效果可以通过添加一个实际的类来达到,而伪元素的效果则需要通过添加一个实际的元素才能达到

CSS3为了区分伪类和伪元素,已经明确规定了伪类用一个冒号来表示,而伪元素则用两个冒号来表示。但因为兼容性的问题,所以现在大部分还是统一的单冒号,但是抛开兼容性的问题,我们在书写时应该尽可能养成好习惯,区分两者
单冒号(:)用于css3伪类双冒号(::)用于CSS3伪元素伪元素由双冒号和伪元素名称组成。不过浏览器需要同时支持旧的已经存在的伪元素写法,比如:first-line、:first-letter、:before、:after等,而新的在CSS3中引入的伪元素则不允许再支持旧的单冒号的写法

伪元素:用于将特殊的效果添加到某些选择器。伪元素代表了某个元素的子元素,这个子元素虽然在逻辑上存在,但却并不实际存在于文档树中

伪类:

 

伪元素:

 

使用css3的animation实现摆钟的效果

 <div class="clock-box">
          <div class="clock"></div>
 </div> 


.clock-box {
             width:300px;
             height:300px;
             margin:100px auto;
             border:1px solid #00ff90;
          }

          .clock {
             width: 2px;
             height: 100px;
             background: #000000;
             margin: 0 auto;
             position: relative;
             -webkit-animation: go 1s ease-in-out alternate infinite;
             /*animation-direction:alternate  规定是否应该轮流反向播放动画*/
             -moz-animation: go 1s ease-in-out alternate infinite;  
             animation: go 1s ease-in-out alternate infinite;

           }
          .clock::after {   //用伪元素设置小球
             content: "";
             position: absolute;
             bottom: -10px; //这个值是为了让小球和竖线看起来在一起 
             left: -10px;  //设置为伪元素的width/2,让其看起来竖线在小球的正中间
             width: 20px;
             height: 20px;
             border-radius: 10px;
             background: #ff0000;
          }


          @keyframes go {
             0% {
                 -webkit-transform: rotate(30deg);
                 -moz-transform: rotate(30deg);
                 transform: rotate(30deg);  //旋转的角度
                 transform-origin: center top; //旋转的中心
                 -webkit-transform-origin: center top;
                 -moz-transform-origin: center top;
              }
              100% {
                 -webkit-transform: rotate(-30deg);
                 -webkit-transform-origin: center top;
                 -moz-transform: rotate(-30deg);
                 -moz-transform-origin: center top;
                 transform: rotate(-30deg);
                 transform-origin: center top;
              }
          }

介绍下css3的animation属性

属性animation配合@keyframes一起实现动画

animation:所有动画属性的简写属性,除了 animation-play-state 属性

animation-name:规定 @keyframes 动画的名称,自己定

animation-duration:规定动画完成一个周期所花费的秒或毫秒。默认是 0,2s

animation-timing-function:规定动画的速度曲线。默认是 "ease"

animation-delay:规定动画何时开始,默认为0

animation-iteration-count:规定动画被播放的次数。默认是 1

 

animation-direction:规定动画是否在下一周期逆向地播放。默认是 "normal"

animation-play-state:规定动画是否正在运行或暂停。默认是 "running"

animation-fill-mode:规定对象动画时间之外的状态

 

css3的transform

transform可以有的属性值

translate(x,y)----水平方向平移

rotate(xdeg)----旋转的度数

scale(num)----缩放

skew(xdeg)------倾斜

 

transform-origin设置旋转元素的基点,默认是本身的中心为旋转的基点transform-origin:center  center

transform-origin: x-axis y-axis z-axis;

/*左上角*/
transform-origin:left top
/*上中间*/  
transform-origin:center top 
/*右上角*/
transform-origin:right top 
/*右中间*/
transform-origin:right center 
/*右下角*/
transform-origin:right bottom 
/*下中间*/
transform-origin:center bottom 
/*左下角*/
transform-origin:left bottom
/*左中间*/ 
transform-origin:left center

 

css3的transition属性介绍

transition 属性是一个简写属性,用于设置四个过渡属性

transition: property duration timing-function delay;

 

 

 

transition和animation的区别

相同点:
(1)指定要监听的CSS属性的变化
(2)设置定时函数改变的一个属性值变换到另一个属性值的速率
(3)指定一个时间来控制动画或过渡会花多长时间
(4)程序式描述动画和过渡的事件
(5)CSS属性变化可视化

 

不同点:
主要体现在触发方式,循环方式,定义关键帧的个数,修改多个css属性的方式,与JS的交互
(1)触发条件不同,transition需要显示触发改变的css的值,animation不需要显示触发。默认自动播放
transition通常和hover等事件配合使用,由事件触发;

一个常见的场景是你使用:hover伪类来改变CSS属性的值;

触发一个过渡的另一种方法是使用JavaScript以编程方式,添加或删除CSS类来模拟一个CSS属性改变

animation动画则不需要任何显式的触发。一旦你定义动画,它将自动开始播放。

(2)循环次数的控制
animation设置循环的次数,通过设置animation-iteration-count:num | infinite,设定固定的循环次数,或者无限循环
transition过渡没有一个属性可以指定多少次运行。当过渡触发时,只运行一次。不过可以通过transitionEnd事件来设置,相对于动画比较复杂


(3) 定义关键帧的个数不一样
animation可以定义多个帧,从而方便控制CSS的属性值,不仅仅是开始和结束
transition只能控制start和end两个关键帧的css属性值


(4) 修改多个属性的方式不一样

/*transition:如果变化涉及到一个以上属性,则需要一次性定义需要改变的css属性*/
#mainContent {
    background-color: #CC0000;
    transition:background-color .5s ease-in, width .5s ease-in
}
#mainContent:hover {
    cursor: pointer;
    background-color: #000000;
    width: 500px;
}


/* animation:则通过帧可以添加任何属性变化 */
@keyframes imageSlide {
    0% {
        left: -150px;
    }


    20% {
        left: 50px;
        height: 200px;
    }


    80% {
        left: 200px;
        height:300px;
    }


    100% {
        left: 600px;
        background-color:#FFFFFF;
    }
}


(5)与JS的相互作用

transition经常跟JS搭配,让js改动属性,从而触发transition的操作,而animation与js的交互不紧密

结论:

1. 如果要灵活定制多个帧以及循环,用animation;如果仅仅是简单的from和to 效果,用 transition

2. 如果要使用js灵活设定动画属性,用transition

 

CSS3 有3种和动画相关的属性:transform, transition, animation

transform 描述了元素静态样式,而transition animation 能实现动画效果,所以transform 常常配合后两者使用

 

 

用原生js动态创建li,然后挂载到dom中,然后点击相应的li输出对应的索引

挂载到dom中有两种方法:设置ul的innerHTML,或者利用createElement()和appendChild()来设置

<style>
  ul{
    display:block;
    list-style: none;

  }
  ul li{
    background:red;
    height:50px;
    font-size:16px;
  }
</style>

<ul class='ul1'></ul>

<script>
  let ul = document.getElementsByClassName('ul1')[0];
  // 两种方式实现挂载,设置innerHTML,或者通过创建li,然后通过appendChild()来设置
  // for(let i=0;i<10;i++){
  //   let li = document.createElement('li');
  //   li.innerHTML = 'fdsfsf';
  //   ul.appendChild(li);
  // }

  
  let str = '';
  for(let i=0;i<10;i++){
    str += '<li>fhdfhu</li>';
  }
  ul.innerHTML = str;
  
  // 挂载之后才能获取到li节点
  let li = ul.children;
  for(let i=1;i<=10;i++){
    li[i-1].onclick = (function(a){
      return function(){console.log(a);}
    })(i);
  }
</script>

 

实现小球的滚动

<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <script src="jquery-3.1.1.min.js"></script>
        <style>
              body{
                  background: black;
              }
              .space{
                  width: 400px;
                  height: 200px;
                  position: relative;
                  border-bottom: 3px solid white;
              }
              .wheel{
                  width: 50px;
                  height: 50px;
                  border-radius: 50%;
                  border: 2px solid white;
                  position: absolute;
                  left: 0px;
                  bottom: 0px;
                  animation: move 3s linear infinite alternate;
              }
              /*用伪元素实现圆形正中间的竖线*/
              .wheel::before{
                  content: "";
                  display: block;
                  position: absolute;
                  /*这些值是根据容器的width  height来设置的*/
                  width: 25px; /*是.wheel的width/2*/
                  height: 2px; /*任意设置*/
                  left: 25px;  /*根据.wheel的width来设置*/
                  top: 25px; /*根据.wheel的height来设置*/
                  background-color: white;  
              }

              @keyframes move{
                  0%{
                      /*初始的时候不需要水平移动和旋转角度*/
                      transform: translateX(0px) rotate(0deg);
                  }
                  100%{
                      /*水平移动的距离=容器width(滚动距离) - 小球的直径*/
                      /*旋转角度 = 水平移动的距离/(小球周长:2*pi*r) *360° */
                      transform: translateX(350px) rotate(802deg);
                  }
              }
        </style>
    </head>
    <body>
        <div class='space'>
            <div class='wheel'>
            </div>
        </div>
        <script>
        </script>
    </body>
</html>
    

这里的轮子是围绕自己的圆心转的,transform-origin:center  center

 

 

用css3实现地球绕太阳转

<!doctype html>
<html>
    <head>
        <meta charset="utf-8"/>
        <script src="jquery-3.1.1.min.js"></script>
        <style>
          body{
            background: #000;
          }
          /*sun也在动,只不过其是绕自身的中心在转动*/
          .sun{
            margin-top: 200px;
            margin-left: 300px;
            width: 280px;
            height: 280px;
            border-radius: 50%;
            border:1px solid #FFA500;
            background:#FFA500;
            box-shadow:0px 0px 35px #FFA500;
            animation:action 10s infinite linear;
          }
          @keyframes action{
            0% { transform: rotate(0deg) }
            100% { transform: rotate(360deg)}
          }
          .earth{ 
            /*让earth偏移sun*/
            margin-left: -90px;
            width: 40px;
            height: 40px;
            border-radius: 50%;
            border:1px solid #0000CC;
            background:#0000CC;
            box-shadow:0px 0px 35px #0000CC;
            animation:actions 5s  infinite linear;
          }

          @keyframes actions{
            0% { 
              transform: rotate(0deg) ;
              transform-origin:center center;
            }
            100% { transform: rotate(360deg)}
          }
          .moon{
            margin-left: -20px;  
            width: 10px;
            height: 10px;
            border-radius: 50%;
            border:1px solid #F0F0F0;
            box-shadow:0px 0px 35px #F0F0F0;
            background:#F0F0F0;             
          }
        </style>
    </head>
    <body>
        <div class="sun">  
          <div class="earth">       
            <div class="moon"></div>
          </div>
        </div>
    </body>
</html>
    

199、实现数字千分位和大写

// 实现千分位转化,只是针对正整数有效,如果是有符号或者小数的话,需要进行处理
let strNum = '1234556';
//正则正向引用
let result1 = strNum.replace( /\d{1,3}(?=(\d{3})+$)/g,function(s){
    return s+',';
} );

console.log(result1);
let result2 = '';
result2 = AmountInWords('1400398');
let result3 = result1 + ' ' + result2;
console.log(result3);

function AmountInWords(dValue, maxDec) 
{
    // 验证输入金额数值或数值字符串:
    dValue = dValue.toString().replace(/,/g, "");  dValue = dValue.replace(/^0+/, "");      // 金额数值转字符、移除逗号、移除前导零
    if (dValue == "") { return "零元整"; }      // (错误:金额为空!)
    else if (isNaN(dValue)) { return "错误:金额不是合法的数值!"; } 
    
    var minus = "";                             // 负数的符号“-”的大写:“负”字。可自定义字符,如“(负)”。
    var CN_SYMBOL = "";                         // 币种名称(如“人民币”,默认空)
    if (dValue.length > 1)
    {
        if (dValue.indexOf('-') == 0) { dValue = dValue.replace("-", ""); minus = "负"; }   // 处理负数符号“-”
        if (dValue.indexOf('+') == 0) { dValue = dValue.replace("+", ""); }                 // 处理前导正数符号“+”(无实际意义)
    }
    
    // 变量定义:
    var vInt = ""; var vDec = "";               // 字符串:金额的整数部分、小数部分
    var resAIW;                                 // 字符串:要输出的结果
    var parts;                                  // 数组(整数部分.小数部分),length=1时则仅为整数。
    var digits, radices, bigRadices, decimals;  // 数组:数字(0~9——零~玖);基(十进制记数系统中每个数字位的基是10——拾,佰,仟);大基(万,亿,兆,京,垓,杼,穰,沟,涧,正);辅币(元以下,角/分/厘/毫/丝)。
    var zeroCount;                              // 零计数
    var i, p, d;                                // 循环因子;前一位数字;当前位数字。
    var quotient, modulus;                      // 整数部分计算用:商数、模数。

    // 金额数值转换为字符,分割整数部分和小数部分:整数、小数分开来搞(小数部分有可能四舍五入后对整数部分有进位)。
    var NoneDecLen = (typeof(maxDec) == "undefined" || maxDec == null || Number(maxDec) < 0 || Number(maxDec) > 5);     // 是否未指定有效小数位(true/false)
    parts = dValue.split('.');                      // 数组赋值:(整数部分.小数部分),Array的length=1则仅为整数。
    if (parts.length > 1) 
    {
        vInt = parts[0]; vDec = parts[1];           // 变量赋值:金额的整数部分、小数部分
        
        if(NoneDecLen) { maxDec = vDec.length > 5 ? 5 : vDec.length; }                                  // 未指定有效小数位参数值时,自动取实际小数位长但不超5。
        var rDec = Number("0." + vDec);     
        rDec *= Math.pow(10, maxDec); rDec = Math.round(Math.abs(rDec)); rDec /= Math.pow(10, maxDec);  // 小数四舍五入
        var aIntDec = rDec.toString().split('.');
        if(Number(aIntDec[0]) == 1) { vInt = (Number(vInt) + 1).toString(); }                           // 小数部分四舍五入后有可能向整数部分的个位进位(值1)
        if(aIntDec.length > 1) { vDec = aIntDec[1]; } else { vDec = ""; }
    }
    else { vInt = dValue; vDec = ""; if(NoneDecLen) { maxDec = 0; } } 
    if(vInt.length > 44) { return "错误:金额值太大了!整数位长【" + vInt.length.toString() + "】超过了上限——44位/千正/10^43(注:1正=1万涧=1亿亿亿亿亿,10^40)!"; }
    
    // 准备各字符数组 Prepare the characters corresponding to the digits:
    digits = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖");         // 零~玖
    radices = new Array("", "拾", "佰", "仟");                                              // 拾,佰,仟
    bigRadices = new Array("", "万", "亿", "兆", "京", "垓", "杼", "穰" ,"沟", "涧", "正"); // 万,亿,兆,京,垓,杼,穰,沟,涧,正
    decimals = new Array("角", "分", "厘", "毫", "丝");                                     // 角/分/厘/毫/丝
    
    resAIW = "";  // 开始处理
    
    // 处理整数部分(如果有)
    if (Number(vInt) > 0) 
    {
        zeroCount = 0;
        for (i = 0; i < vInt.length; i++) 
        {
            p = vInt.length - i - 1; d = vInt.substr(i, 1); quotient = p / 4; modulus = p % 4;
            if (d == "0") { zeroCount++; }
            else 
            {
                if (zeroCount > 0) { resAIW += digits[0]; }
                zeroCount = 0; resAIW += digits[Number(d)] + radices[modulus];
            }
            if (modulus == 0 && zeroCount < 4) { resAIW += bigRadices[quotient]; }
        }
        resAIW += "元";
    }
    
    // 处理小数部分(如果有)
    for (i = 0; i < vDec.length; i++) { d = vDec.substr(i, 1); if (d != "0") { resAIW += digits[Number(d)] + decimals[i]; } }
    
    // 处理结果
    if (resAIW == "") { resAIW = "零" + "元"; }     // 零元
    if (vDec == "") { resAIW += "整"; }             // ...元整
    resAIW = CN_SYMBOL + minus + resAIW;            // 人民币/负......元角分/整
    return resAIW;
}

实现数字大写:只是简单转换,没有考虑边界因素

function turnLowerToUpper(num){
  let str = num.toString(),
      zeroCount = 0,
      digits = new Array("零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"),
      radices = new Array("", "拾", "佰", "仟"),
      bigRadices = new Array("", "万", "亿", "兆", "京", "垓", "杼", "穰" ,"沟", "涧", "正"),
      ret = '',
      len = str.length,
      p,
      val,
      rem;
  for( let i=0;i<len;i++ ){
    char = str.charAt(i);
    p = len-1-i;
    val = parseInt(p/4);
    rem = parseInt(p%4);
    if( char == '0' ){
      zeroCount++;
    }else{
      if( zeroCount > 0){
        ret += digits[0];
      }
      zeroCount = 0;
      ret += digits[parseInt(char)] + radices[rem];
    }

    if( rem==0 && zeroCount<4 ){
      ret += bigRadices[val];
    }
  }
  return ret;
}  

console.log(turnLowerToUpper(12345678))

 

 

 

 

200 、js中实现私有变量的方法

在ES6之前,作用域只包括全局作用域和函数作用域,实现私有变量是通过在函数内定义变量,然后通过闭包去访问该私有变量;

在ES6中是通过在constructor里面定义变量,然后通过set和get来设置和获取私有变量的值

   var Book = function(newIsbn, newTitle, newAuthor){
       //private attributes
       var isbn, title, author;

       this.name = 'jiang';
       //privileged methods
       this.getTitle = function(){
          //返回变量title,而不是this.title
          return title;
       }
       this.setTitle = function(newTitle){
          title = newTitle || 'No title specified'
       }
       //Constructor code
       this.setTitle(newTitle);
   }
   //Public, non-privileged methods
   Book.prototype = {
       display: function(){
           console.log(this.getTitle());
       }
   }
   var book = new Book('a', 'book1', 'sysuzhyupeng');
   console.log(book.getTitle());  // 'book1'
   console.log(book.title)       // undefined,只能通过上面的方法访问
   console.log(book.name);     //jiang,在函数中通过this声明的属性

在es5中就已经可以通过definedProperty方法中的访问器,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

var book = {
      //不能是title,必须与title不同,这里使用常用命名规范,在前面加了下划线
      _title: 'book1'
   }
   Object.defineProperty(book, 'title', {
      get: function(){
         //同样不能是title,使用_title
         return this._title;
      },
      set: function(value){
         value == 'book2' ?
         this._title = value : '' 
      }
   })
   book.title   // 'book1'
   book.title = 'book3'; 
   book.title  // 'book1'
   book.title = 'book2';
   book.title  // 'book2'

es6的写法,也是通过中间变量来访问私有属性的

class Book {
   constructor(name){
      this._title = name;
   }
   get title(){
      return this._title;
   }
   set title(value){
      this._title = value;
   }
}
var book = new Book('book1');
console.log(book.title);// 'book1'

book.title = 'book3'; 
console.log(book.title);// 'book3'
 
book.title = 'book2';
console.log(book.title ) // 'book2' 

 

200 、匹配普通邮箱的正则表达式

let reg = /^\w+[-.\w]*@(\w+(-\w+)?\.)+[a-z]{2,6}/

201 、实现单位的转换,bps    Kbps     Mbps    Gbps    Tbps,如 1000 bps 转换结果为1 Kbps,四舍五入,保留2位小数,如果两位小数位0,则取整

let str = '1000';
let num = parseInt(str,10);

let len = str.length;
let tmp;
let ret = '';
let unit = ''
if( len<4 ){
    tmp = str;
    unit = 'bps';
}else if( len>=4 && len <=6 ){
    unit = 'Kbps';
    tmp = ( num/1000 ).toFixed(2)
}else if( len >=7 && len <= 9 ){
    unit = 'Mbps';
    tmp = ( num/1000000 ).toFixed(2)
}else if( len>=10 && len <=12 ){
    unit = 'Gbps';
    tmp = ( num/1000000000 ).toFixed(2)
}else{
    unit = 'Tbps';
    tmp = ( num/1000000000000 ).toFixed(2)
}
// 保留两位小数,如果小数位1.00则变成1
if( (tmp - parseInt(tmp,10)) < Number.EPSILON ){
    tmp = parseInt(tmp);
}

// 加上单位
ret = tmp +" " +  unit;
console.log(ret)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值