【77】JS数组 函数 对象 算法练习题(小白思路VS更优思路)

★文章内容学习来源:拉勾教育大前端就业集训营


本篇学习目标:
1.识别小白思路之弊端,掌握更优思路




一、数组

1. 统计大于等于平均成绩的人数

  • 有10个学生的成绩存在数组中,请统计大于等于平均成绩的人数。
  • 成绩直接以数组形式写在程序中,不需要用户输入。

这一题比较基础,涉及数组的定义以及数组长度与项之间关系:

var grades = [60,70,80,56,38,95,67,88,100,75];
//console.log(grades);
sumgrades = 0;
 for (i = 0 ; i <= grades.length-1 ; i++) {
   
     sumgrades += grades[i];
}
//console.log("所有人分数之和="+sumgrades);
 var  av = sumgrades / grades.length;
 // console.log("平均分="+av);
 //计数:大于平均分的人数
 var count =0;
 for (i = 0 ; i <= grades.length-1 ; i++) {
   
      if (grades[i] > av) {
   
               count++;
        }
 } 
 console.log("大于等于平均成绩"+av+"的人数有"+count+"人");


2. 数组中的最大值和最小值,以及所在位置的下标

  • 求一组数中的最大值和最小值,以及所在位置的下标。

比较简单的方法如下,灵活运用中间变量:

var arr = [2,4,1,5,3,9,10,8,7,6];
console.log(arr);
//定义中间变量,储存比较过程中的最大值最小值以及对应下标
  var max = 0; //最大值的初始值必须是最小的
  var min = 20;  //最小值的初始值必须是最大的
  var max_index = 0;
  var min_index = 0;
//循环遍历数组进行比较
for (var i = 0; i <= arr.length-1 ; i++) {
   
    //比较是否比最大值更大
    if (arr[i] > max) {
   
           max = arr[i];
           max_index = i;
     }
         //比较是否比最小值更小
    if (arr[i] < min) {
   
           min = arr[i];
           min_index = i;
   }
} 
 //输出
console.log("最大值"+ max+"所在下标为"+max_index);
console.log("最小值"+ min+"所在下标为"+min_index);

也可以用到内置对象中的一些方法:

//①定义一组数 
var arr = new Array(2,4,1,5,3,9,10,8,7,6);
console.log(arr);
//②数组转字符串,之后找位置可以借助字符串,因为数组排序后顺序会变
 var char = arr.join("");
//console.log(char);//转数组成功
//③从大到小给数组排序
arr.sort(function(a,b) {
   
     if (a > b) {
   
               return -1; //a在b前,越大越在前,说明是从大到小排序
     } else if (a < b) {
   
               return 1; //a在b后
     } else {
   
              return 0; //a和b保持原来位置
     }
});
//④排序后数组的第一个是最大值,最后一个是最小值//数组顺序变了,所以从之前转号的字符串中找两个值所在位置
console.log("最大值"+arr[0]+"所在位置下标"+char.indexOf("10"));
console.log("最小值"+arr[arr.length-1]+"所在位置下标"+char.indexOf("1"));






二、函数

1.完美数

  • 使用函数方法书写一段程序,判断一个数是不是完美数。 如果一个数恰好等于它的因数之和,则称该数为“完美数”。
  • 例如:第1个完全数是6,它有因数1、2、3、6,除去它本身6外,其余3个数相加,1+2+3=6。

小白思路:刚开始学习这里的我,容易写成以下形式,虽然也可以成功实现效果,但是违背了函数的作用:让函数的功能模块化(单一),并且可以尽量在任何需要它的地方再次调用

 function fun1 (a = prompt("请输入一个整数","6")) {
   
      sum = 0;  
      for (i = 1; i <= a ; i++) {
   
           if (a % i == 0) {
   
                sum += i;
           } 
       }
        if (sum == 2*a) {
   
                alert(a+"是完美数");
       } else {
   
                alert(a+"不是完美数");
       }             
}
fun1();

1.更优思路:需要把其中涉及到函数单独拎出来,模块化,实现单一的功能。
2.思考顺序: 判断→需要用户先输入→需要知道怎么判断完美数→需要知道约数和情况。而写代码实现思路与之相反~也就是逆向思维
3.写代码实现顺序:设置约数和函数→设置判断完美数函数→用户输入→判断
4.虽然下例代码看起来更多,但是却可以在更多的场合调用,真正实现了函数的作用

//约数和函数(约数和情况)
  function yueshuhe(a) {
   
     //累加器
    sum = 0;
    for (var i = 1; i < a ; i++) {
   
        if (a % i === 0){
   
            sum += i;
         }
    }
     //循环结束后,sum中储存了a的约数和
    return sum;
 }
 //判断完美数函数(怎么判断完美数)
  function isWm(a) {
   
       if (yueshuhe(a) === a) {
   
              return true;
        }else {
   
              return false;
       }
   }
//用户输入
var n = parseInt(prompt("请输入一个数,会自动判断其是否为完美数","6"));
//判断用户输入是否为完美数并且弹出结果
    if (isWm(n)){
   
            alert(n+"是完美数");
    } else {
   
            alert(n+"不是完美数");
    }

2. 盈数

  • 求2000 以内的全部亲密数。
  • 盈数是一种特殊的自然数,除去它本身以外的一切正约数的和大于它本身。与完美数类似。

小白思路:刚开始学习这里的我,容易写成以下形式,虽然也可以成功实现效果,但是违背了函数的作用:让函数的功能模块化(单一),并且可以尽量在任何需要它的地方再次调用。与上题犯错情况类似

 function fun () {
      
     for (a = 1 ; a < 100; a++) {
   
       sum = 0; //累加器初始化位置很重要!因为每次是一个a对应它所有的i(因数)之和,所以再a的循环之内
       for(i = 1 ; i < a ; i++) {
   
            if (a % i == 0) {
   
               sum += i; 
              //因为上面定义了i<a,所以这里的sum就是除了a本身的所有a的因数i之和
           }  
       }
        //console.log(a +"的因数和为"+sum); 
        if (sum > a ) {
   
              console.log(a+"是盈数");
       }
   }
}
        fun ();

1.更优思路:需要把其中涉及到函数单独拎出来,模块化,实现单一的功能。
2.思考顺序:输出盈数→需要知道怎么判断盈数→需要知道约数和情况
3.代码书写顺序:约数和函数→判断盈数函数→输出盈数函数→调用

 //约数和函数(与上题一样):输入参数a,输出a的约数和
function yueshuhe(a) {
   
    sum = 0;
     for (var i = 1; i < a;i++) {
   
          if (a % i === 0) {
   
              sum += i;
          }
    }
    return sum;
}
//判断盈数函数:
function isYs(a) {
   
    if (yueshuhe(a) > a) {
   
            return true;
     }else {
   
             return false;
     }
}
//输出盈数函数:传入一个参数b,输出1-b之间所有盈数
 function scYs(b) {
   
   for (i = 1;i <= b; i++) {
   
       if (isYs(i)) {
   
            console.log(i+"是盈数");
       }
   }
 }
//调用
scYs(100);

3. 1! + 2! + 3! + 4! + …… + n!

  • 用户输入一个整数n,求1! + 2! + 3! + 4! + …… + n!的和。

小白思路:多分支语句+调用函数。
缺点:不易在其它需要用到的地方调用,函数模块化的作用未能很好体现。

function fun (a = parseInt(prompt("请输入一个整数n","4"))) {
   
      if (a == 1) {
   
                return 1*1;
      } else if (a == 2) {
   
                return 1*1 + 2*1;
     }  else if (a > 2) {
   
                return a*(fun(a-1)-fun(a-2)) + fun(a-1);
     }
}
alert("1!+2!+……+n!="+fun());

更优思路:函数模块化。

//求阶乘函数(输入一个数,返回这个数的阶乘)
function jc(a) {
   
   //累乘器
    var mul = 1;
    for (var i =1; i <= a;i++) {
   
          mul *= i;
    }
     return mul;
}
//求阶乘和函数(传输一个整数a,返回从1!加到a!的和)
function jch(a) {
   
    //累加器
    var sum = 0;
   for (var i =1; i <= a ;i++) {
   
       sum += jc(i);
   }
   return sum;
}
//用户输入
 var n = parseInt(prompt("请输入一个整数","4"));
//调用阶乘和函数
alert("1!+2!+……+n!="+jch(n));

4. 喇叭花数

  • 求一个三位数,叫做“喇叭花数”,该三位数等于其每位数字的阶乘之和。
  • 输出100~999的所有喇叭花数。

小白思路:仍然是与上几道题一样的情况,没有很好地把函数模块化的特点显示出来。

//求一个三位数,叫做“喇叭花数”,该三位数等于其每位数字的阶乘之和。
function fun () {
   
      for (a = 100 ; a <= 999; a++) {
   
           var g = a % 10,
               s = parseInt(a / 10) % 10,
               b = parseInt(a / 100);
                    //console.log(a+"个位为"+ g);
                    //console.log(a+"十位为"+ s);
                    //console.log(a+"百位为"+ b); 
           mulg = 1;
           for (var i = g; i >= 1 ; i--) {
   
              mulg *= i;
            }
          //console.log(a+"个位数的阶乘为"+mulg);
           muls = 1;
           for (j = s; j >= 1; j--) {
   
               muls *= j;
           }
           //console.log(a+"十位数的阶乘为"+muls);
           mulb  = 1;
           for (h = b; h >= 1; h--) {
   
                 mulb *= h;
           }
           //console.log(a+"百位数的阶乘为"+mulb);
          //判断各个位数的阶乘之和是否等于这个数,是的话输出为喇叭花数
          if (a == mulg + muls + mulb) {
   
                 console.log(a+"是喇叭花数");
          }       
     }
 }
        fun();

更化思路:将第3题中遇见的求阶乘函数运用在其中,且再定义一个判断喇叭花数的函数。更能体现出函数的作用。

//思路:输出100~999的所有喇叭花数→需要知道怎么判断喇叭花数→需要知道一个数的阶乘怎么求
//阶乘函数
function jc(a) {
   
 mul = 1;
 for (i = 1;i <= a;i++) {
   
     mul *= i;
  }
 return mul;
}
//判断喇叭花数函数
function isLbh(i) {
   
//拆分位数
  var g = i % 10;
  var s = parseInt(i / 10) % 10;
  var b = parseInt(i / 100);   
 //计算各个位数阶乘之和
   var sum = jc(g)+jc(s)+jc(b);
 //判断与i是否相等
  if (sum === i) {
   
        return true;
  } else {
   
        return false;
  }
}
//输出100~999的所有喇叭花数 
for (var j = 100; j <= 999; j++){
   
   if (isLbh(j)){
   
     console.log(j+"是喇叭花数");
   }
}


5. 亲密数

  • 求2000 以内的全部亲密数。
  • 如果整数A 的全部约数(包括1,不包括A 本身)之和等于B,且整数B 的全部约数(包括1,不包括B 本身)之和等于A,则称整数A和B是一对亲密数。

更优思路:因为以上几道题都展示了小白思路,总的来说就都是不具有函数模块化的思想,所以我们要额外注意这一点,那这里就直接展示更有思路啦!

// 思路:输出亲密数 → 判断亲密数 → 约数和函数

// 求约数和函数
// 说明:传入一个整数,返回这个整数的约数和
function yueshuhe(a) {
   
    var sum = 0;// 累加器
	// 循环累加约数
	for(var i = 1 ; i < a ; i++){
   
		if(a % i === 0){
   
			sum+=i;
		}
	}
	// 循环结束后,sum 中存了 a 的约数和
	return sum;
}

// 制作判断亲密数函数
// 说明:输入一个数,判断是否有亲密数
function isQm(a) {
   
	// 一个数如果有亲密数,那么这个亲密数肯定是 a 的约数和
	// 直接求 a 的约数和
	var b = yueshuhe(a);
	// 反推 b 的约数和是否等于 a,如果相等就是亲密数,a 不能等于 b
	if (yueshuhe(b) === a && a != b) {
   
			return true;
	}else{
   
			return false;
	}
}

// 直接输出 2000 以内的亲密数
for (var i = 1 ; i <= 2000 ; i++) {
   
	var j = yueshuhe(i);
	if (isQm(i) && j <= 2000) {
   
	   console.log(i+"和"+j+"是亲密数");
	}
}


6.验证哥德巴赫猜想

  • 哥德巴赫猜想:一个偶数可以拆分成两个质数之和。

更优思路:

// 用户输入
var n = parseInt(prompt("请输入一个大于2的偶数"));
        
// 判断质数函数
// 说明:输入一个数,返回是否是质数
function isZs(a) {
   			
// 循环累加,看在 2 到根号 a 之间有没有其他约数,有就肯定不是质数,直接返回
	for (var i = 2 ; i <= Math.sqrt(a) ; i++) {
   
		if(a % i === 0){
   
		// 说明肯定不是质数
			return false;
		}
	}
// 如果能走到这个位置,说明没遇到 return,没有其他的约数,就是质数
	if (a != 1) {
   
		return true;
	}else{
   
		return false;
			}
	}
// 输出 n 的所有质数之和的可能性
for (var i = 2 ; i <= n / 2 ; i++) {
   
	// 定义另一个质数可能性
	var j = n - i;
	// 判断 i 和 j 同时都是质数,输出
	if (isZs(i) && isZs(j)) {
   
	  console.log(n + "可以拆分成两个质数" + i + "与" + j + "的和");
	}
}
        


三、数组与函数综合

1. 买卖股票的最大利润

给定一个数组,它的第i个元素是一支给定股票第i天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次)设计一个算法来计算你所能获取的最大利润。
注意:你不能再买入股票前卖出股票!

示例:输入:[7, 1, 5, 3, 6, 4]输出:5
解释:在第2天(当天股票价格等于1)的时候买入,在第五天(当天股票价格等于6)的时候卖出,最大利润为 6 - 1 = 5。
注意:利润不能使7 - 1 = 6,因为第二天的价格为1,第一天的价格为7,你是不可能在第二天买入股票然后等到第一天卖出的。

 function shares(arr) {
   
     var max_out = 0;//最大利润的初始值
     var max_in = arr[0];//买入价初始值
     for (var i = 1; i <= arr.length -1;i++) {
   
             if (arr[i] < max_in ){
   
                 max_in = arr[i]; //买入价有更低的了,所以替换
             }  
             if (arr[i] - max_in > max_out){
   
                 max_out= arr[i]-max_in; //利润有更大的了,所以替换
             }
         }
         return max_out; //返回最大利润值
}
//定一个一个数组调用函数
   var arr = [7, 1, 5, 3, 6, 4];
   console.log(shares(arr));


2. 去除数组中指定数

将数组中值为 0 的项去掉,将不为 0 的值存入一个新的数组,生成新的数组。

小白思路:单一实现某数组中的0项去掉。
更优思路:如下,考虑成一个具有指定项去除的功能的函数,下次调用函数用在别的数组中去除别的指定数也一样可行。

//定义此功能函数removeN(arr,num)
 //说明:arr是数组,num是指定要去除的项
function removeN(arr,num) {
   
    var newArr = [];//空数组用于将来接受去除num后的所有项,形成新数组
     //遍历数组
     for (var i = 0 ; i <= arr.length-1;i++) {
   
      //如果原数组中遇到不是num的项,则加入到新数组中
      if (arr[i] != num) {
   
           newArr.push(arr[i]);
      }
    }
  return newArr;
} 
var arr = [0,2,0,0,0,0,70,0,0,0,0,9,44,0,0,0];
//调用函数num=0
console.log(removeN(arr,0));



四、对象

1. 数组去重

比如数组 [1,1,1,2,2,3,4,5,6,3,4,2,4,1]去重结果为 [1,2,3,4,5,6]
这一类题,老师说面试常考哦!目前所学知识可以想到以下两种方法。

方法1:利用内置对象数组的splice方法,for循环与条件分支if语句

var arr = [1,1,1,2,2,3,4,5,6,3,4,2,4,1];
console.log(arr);
//比较第i项和后面项是否相同,如果相同就删除后面项
function uique(arr) {
   
    for (var i = 0; i < arr.length; i++) {
   
         //比较
         for (var j = i + 1; j < arr.length;j++) {
   
              //如果前后相同,删除后一项
            if (arr[i] === arr[j]) {
   
                arr.splice(j,1);
                j--; //因为后一项被删除了
            }
        }
    }
    return arr;
}
console.log(uique(arr));

方法2:利用内置对象数组的indexOf方法

var arr = [1,1,1,2,2,3,4,5,6,3,4,2,4,1];
console.log(arr);
function unique(arr) {
   
    //定义一个新数组去接收不重复部分
     var newArr = [];
    //循环遍历有重复的数组
     for (var i = 0; i < arr.length; i++) {
   
        //如果i项不存在新数组中,就加入
         if (newArr.indexOf(arr[i] )=== -1) {
   
              newArr.push(arr[i]);
         }
     }
    return newArr;
}
console.log(unique(arr));


2. 数组转对象

  • [‘a’,‘a’,‘a’,‘b’,‘b’,‘c’,‘c’,‘c’,‘c’,‘d’,‘d’,‘d’,‘d’] —> {a: 3,b: 2,c: 4,d: 4}
    相当于给一个空对象添加数据。
arr = ['a','a','a','b','b','c','c','c','c','d','d','d','d'];
console.log(arr);
//定义一个作用是数组转成对象的函数,其参数arr是数组
   function transformToObj(arr) {
   
       //定义一个空对象,用于接受数据
       var obj ={
   };
       //循环遍历数组
       for (var i =0; i < arr.length; i++) {
   
          //如果数组中的项在对象中不存在,那就给这个属性值赋值为1
          if (!obj[arr[i]]) {
   
             obj [arr[i]] = 1;
         }else {
   
         //反之,如果数组中的项在对象中存在,那就在原有基础上+1
            obj [arr[i]] +=1;
         }
      }
        return obj;
  }
 console.log(transformToObj(arr));



3 .数组排序

  • [3,4,1,2,6,5,8,9,10,7] —> [1,2,3,4,5,6,7,8,9,10]

错误示例:直接使用sort()方法,不做任何更改
因为sort是默认按照unicode编码大小排序的

var arr1 = [3,4,1,2,6,5,8,9,10,7];
        //方法1:sort()方法
function paixu(arr) {
   
            arr.sort();
            return arr;
}
console.log(paixu(arr1));

正确示例:使用sort()方法时,更改其中参数关系
可以参见【76】二、内置对象2. Array对象(3) 数组常用方法及举例⑥顺序相关sort()

  • 简单来说:返回值是负数:a排在b前面。返回值是正数:a排在b后面。返回值是0:a和b的顺序保持不变。
var arr1 = [3,4,1,2,6,5,8,9,10,7];
//方法1:sort()方法
function paixu(arr) {
   
     arr.sort(function(a,b){
   
          return a-b; //只有a比b小,才会是负值,a排在前,所以从小到大排序
     });
 return arr;
 }
console.log(paixu(arr1));

纯数字数组排序还有其它方法,以下介绍三种:冒泡排序、选择排序、插入排序。

冒泡排序: 具体介绍可以参见百度。
一般把数组原先的顺序按照垂直方向写,从底到顶依次写好,从第一项开始,两两比较,大的往上拿,最后大的都在数组后面,也就是从小往大排序。

//冒泡排序
var arr = [3,4,1,2,6,5,8,9,10,7];
//外层:冒泡次数=项数-1,所以i<arr.length
for (var i = 1; i < arr.length; i++) {
   
    //内层:第i次冒泡要比较arr.length-i次
    //第1次冒泡,要比较9次
    //第2次冒泡,要比较8次
    //第7次冒泡,要比较7次
    //...
    for(var j = 0; j < arr.length-i; j++){
   
        //如果前项数>后一项,那就把大的前一项往后拿
        if (arr[j] > arr[j+1]) {
   
            var jval = arr[j]; //先把大的前一项赋值给中间变量
            arr[j] = arr[j+1]; //再让小的后一项负值给前一项位置
            arr[j+1] = jval;  //最后让大的值赋值给后一项位置
        }
    }
}
console.log(arr);

选择排序:从下标为0的(也就是第一项)开始作为对比项,与其后所有项对比,其后所有项中最大的数作为目标项,目标项和对比项交换下标(也就是换位置)。

var arr = [3,4,1,2,6,5,8,9,10,7];
//对比项循环,从下标为0开始,到倒数第二项为止,如果到最后一项就没有目标项了
for (var i = 0; i < arr.length-1; i++) {
   
    //记录一下当前对比项的下标i,当作判断依据
    var m = i; //也默认第i项最大
    //判断i以后的所有项中,有没有比第i项大,如果有,替换掉下标
    //也就是寻找目标项
    for (var j = i+1; j < arr.length; j++) {
   
        if (arr[j] > arr[m]) {
     //如果这里的判断条件改为小于号,则为小的往前移,相当于从小往大排序
            m = j;  //大的往前移,相当于从大到小排序
        }
    }
    //如果这时候的m=j与原先的i不等(也就是位置不一样),就替换位置,利用中间变量old
    if (m !== i) {
   
        var old = arr[i]; //让i位置的值(对比项)赋值给old
        arr[i] = arr[m]; //让m位置的值(目标项)赋值给i位置
        arr[m] = old; // 让old(此时里面储存着原先的对比项值)赋值给m位置
    }
}
console.log(arr);

插入排序:从第2项(也就是arr[1])开始往前比,大的往后挪

var arr = [3,4,1,2,6,5,8,9,10,7];
//外层循环从下标为1的项开始,与前比较
for (var i = 1; i < arr.length; i++) {
   
    //定义一个对比项下标
    var m = i - 1; //因为是往前比
    //记录当前循环到的数据项,因为这一项可能会被替换掉,而后面可能要插入到别的位置
    var current = arr[i];
    //判断i以前的项,有无比i项大的,有则往后排
    //最终到下标为0结束,如果期间遇见比i小的,则停止循环判断
    while (m >= 0 && arr[m] > current) {
   
        arr[m+1] = arr[m]; //往后排
        m--;
    }
    //循环结束后,要么m=-1,要么就是当前的m项比i项小
    arr[m+1] = current; //将原来的i项插入到m项之后
}
console.log(arr);

4. 将数组用 | 或其他符号连接成一个字符串

小白思路:可以实现效果,但是不如更优思路可重复利用性高。

  //思路:①定义一个数组
  var arr =[1,2,3,4,1,5,4];
   //输出数组
  console.log(arr);
  //思路:②用数组的join方法转成字符串
  char = arr.join("|");
  //输出字符串
   console.log(char);

更优思路1:将此功能定义给函数,直接使用join方法

var  arr = [1,2,3,4,1,5,4];
//方法1,将此功能定义给函数,直接使用join方法
//函数说明:两个参数,arr数组,mark连接的符号
function connect(arr,mark) {
   
     return arr.join(mark); //使用join方法直接转为字符串
}
console.log(connect(arr,"|"));

更优思路2:将此功能定义给函数,数组遍历

//方法2:数组遍历
function connect(arr,mark) {
   
  var str = "" +arr[0]; //+的拼接功能,只要有一边是字符串,那整体结果就是字符串
   //是从下标为1开始的左边有mark的
    for (var i = 1; i < arr.length; i++) {
    
           str +=  mark + arr[i] ;
    } 
     return str;
}
 console.log(connect(arr,"|"));

5. 实现将字符串倒置

  • 编写函数rev(char) 实现将字符串char倒置,比如rev(“spring”) 返回"gnirps"。

小白思路:如下用了函数,也做到了模块化,但是还是可以优化!

var char = "spring";
console.log(rev(char));
function rev(char) {
   
 //思路:可以先把字符串转换为数组,数组中有reverse()方法,然后再把数组转回字符串:
   //转为数组
   var arr = char.split("");
  //数组倒序
   arr.reverse();
  //数组转为字符串
    char =arr.join("");
    return char;
}

更优思路:链式调用
因为以上用到的内置对象的方法中,都有返回值,可以直接进行调用,优化如下

var char = "spring";
console.log(rev(char));
function rev(char) {
   
   return  char.split("").reverse().join("");
}

6. 将字符串语句倒置

  • 将字符串"i come from beijing"倒置,即控制台输出"beijing from come i"
  • 语句直接写在程序中,不需要用户输入

小白思路:可以实现效果,但是不利于复用,同时也可以和上题一样考虑一下链式调用。

//定义字符串
   var str = "i come from beijing";
   console.log(str);
//将数组转为数组 
var arr = str.split(" ");//以空格为分割
//console.log(arr);
//数组倒置
var rarr = arr.reverse();
//console.log(rarr);
//数组转回字符串
var str = rarr.join(" ");//以空格隔开
console.log(str);

更优思路:其实这题更多是考察能否在函数的参数中封装“分隔符”

        var str = "i come from Beijing";
       //函数说明:参数char是字符串,参数s是分割符
        function rev(char,s) {
   
            char = char.split(s).reverse().join(s);
            return char;
        }
         console.log(rev(str," "));


7. 实现字符串循环右移n位

  • 编写函数rightchange(char,n) 实现字符串char循环右移n位。
  • 比如rightchange("abcdefg",2) 返回"fgabcde"

小白思路:①字符串转为数组②尾删→首添③转回字符串,用了函数调用。
但代码量大,且不利于复用。

        //思路:①字符串转为数组②尾删→首添③转回字符串
        function rightchange (char,n) {
   
            //输入字符串
            var char = prompt("请输入一个字符串,会执行循环右移","abcdefg");
            //①字符串转数组
            var arr = char.split("");
            console.log("第一次字符串转数组"+arr);//数组转成功 
            function xhws(n) {
   
                if (n == 1) {
   
                 //②分支-循环右移1位:数组尾删的数加到首部
                 return arr.unshift(arr.pop());
                } else if (n > 1) {
   
                  //②分支-右移大于1位:不断数组尾删的数加到首部,函数递归
                 return arr.unshift(arr.pop(xhws(n-1)));
               }
            }
            //调用
            xhws(n = prompt("请输入您要循环右移的位数","1"));
            //输出右移数组
            console.log("循环右移"+ n +"位后的数组"+arr);//右移成功
            //③转回字符串
            char = arr.join(""),
            console.log("转回字符串的结果"+char);//转回字符串成功
            alert(char);
        }
        rightchange();

更优思路1:用for循环来进行需要重复的unshiftpop方法,整体一个函数更加清晰明了。

//定义函数 
function rightChange(char,n) {
   
 n = n % char.length; //根据多次右移发现这个规律,这样循环次数可以减少
var arr = char.split("");//字符串转数组
 //循环让数组尾删→首添n次
for (var i = 1; i <= n ;i++) {
   
    arr.unshift(arr.pop());
}
 char = arr.join(""); //数组转回字符串
 return char;
}
//调用函数
var char = prompt("请输入一个字符串","abcdefg");
var n = parseInt(prompt("请输入您想右移的位数","1"));
 alert(rightChange(char,n));

更优思路2:根据n的数值,字符串截取(截成两段),之后把两段颠倒顺序再拼接

//方法2:根据n的数值,字符串截取(截成两段),之后把两段颠倒顺序再拼接
function rightChange(char,n) {
   
    n = n % char.length;
    var str1 = char.slice(0,-n);//开始于第0位,截止于从后往前数第n位(不包括)。
    var str2 = char.slice(-n);//开始于从后往前数第n位,截止于结束。
    char = str2 + str1;
    return char;
}
var char = prompt("请输入一个字符串","abcdefg");
var n = parseInt(prompt("请输入您想右移的位数","1"));
alert(rightChange(char,n));

8. 返回字符串中最长的连续重复字母

  • 编写函数maxr(char) 返回字符串char中最长的连续重复字母。

常见思路:二指针法:一个基准值,一个移动,同时使用中间变量存储过渡值(最长子串,最长长度)。

情况1:一个字符串中只有一个最长连续重复字母:
比如 maxr("mmmiijjjjkkkkkkssptr") 返回"kkkkkk"

console.log(maxr("mmmiijjjjkkkkkkssptr"));
function maxr(char) {
   
     var a = 0,//基准值
         b = 1;//移动
     var maxLength = 0;//最长子串长度,初始值0
     var maxChar = ""; //最长子串,初始值""
     //基准值的循环从0开始,到倒数第二个结束
     while (a <= char.length-2) {
   
       //每次都比较a位置与b位置是否一样
       if (char.charAt(a) === char.charAt(b)) {
   
                //如果相等就给b加1,进入下一次循环
                b++;
        }else {
   
              //不相等,则与原先的最长子串比较,存储现最长子串情况
                if (b - a > maxLength) {
   
                    maxLength = b - a;
                    maxChar = char.slice(a,b);
               }
                //a基准值该换位置了,储存完成这次数据,进入下一次比较时
                 a = b;
                 b = a + 1;
        }
     }
   return maxChar;
    }

情况2:一个字符串中不止一个最长连续重复字母:
比如maxr("mmmiijjjjkkkkkksssssspppppptr")返回"kkkkkk", “ssssss”, “pppppp
解决办法:可以把maxChar定义为数组

console.log(maxr1("mmmiijjjjkkkkkksssssspppppptr"));
function maxr1(char) {
   
    var a = 0,
        b = 1;
    var maxChar = [""]; //数组
    var maxLength = 0;
    while (a <= char.length -2) {
   
        if (char.charAt(a) === char.charAt(b)) {
   
            b++;
        }else {
   
            if (b -a > maxLength) {
   
                maxLength = b - a ;
                maxChar = [char.slice(a,b)];//数组中添加数据
            } else if (b - a === maxLength) {
   
                maxChar.push(char.slice(a,b));//在 maxChar数组中往后添加字符串数
            }
            a = b;
            b = a  + 1;
        }
    }
    return maxChar;
}


9. 将一句英文每个单词的第一个字母,变为大写

  • 比如将"i love javascript very much"的每个单词的第一个字母,变为大写。
//思路:转为数组→循环遍历数组将首字符大写并再拼接上原来首字母后面的→转回字符串
var char = "i love javascript very much";
console.log(char); //原字符串输出做对比
console.log(firstLetterup(char));//调用下面函数后
function firstLetterup(char) {
   
    arr = char.split(" ") //字符串转数组,数组中每一项是以" "为分隔符隔开的
    for (i = 0; i <= arr.length-1; i++) {
   
    //具体的每一项还是个字符串可以用charAt方法定到首字母,用toUpperCase将其转为大写,但是整体上还需要拼接上原来每一项的除了首字母外的其它字符用+号和slice方法
    //链式调用
      arr[i]= arr[i].charAt(0).toUpperCase()+arr[i].slice(1);
    }
    str = arr.join(" ");//转回字符串
    return str;
}



10. 九九乘法表

     //思路:将乘法表横着看
     //两层for循环,外层是1-9;
     //内层对应外层,外层是几,内层就循环到几
     for (var i = 1; i <= 9; i++) {
   
         var str = " "; //字符串拼接,有点像“累加器”
         for (var j = 1; j <= i; j++) {
   
         str += i +"×"+j+"="+i*j+" ";
         }
         console.log(str+"\n"); //每循环一次外层,就换一次行
     }



下篇继续:【xx】xxxxxxxxxx

全部评论

相关推荐

10-11 15:42
皖西学院 Java
青鱼LINK:我硕士,也是java0面试,吾道不孤
点赞 评论 收藏
分享
11-24 00:11
已编辑
广东工业大学 算法工程师
避雷深圳&nbsp;&nbsp;yidao,试用期&nbsp;6&nbsp;个月。好嘛,试用期还没结束,就直接告诉你尽快找下一家吧,我谢谢您嘞
牛客75408465号:笑死,直属领导和 hr 口径都没统一,各自说了一些离谱的被裁理由,你们能不能认真一点呀,哈哈哈哈哈😅😅😅
点赞 评论 收藏
分享
评论
点赞
2
分享
牛客网
牛客企业服务