牛客编程题刷题记录----day02

牛客的算法题—day02

牛客–BM2 链表内指定区间反转

描述

将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
例如:
给出的链表为 1→ 2 → 3 → 4 → 5 → NULL,1→2→3→4→5→NULL, m=2,n=4,

返回 1→ 4→ 3→ 2→ 5→ NULL

数据范围: 链表长度 0 < size \le 10000<siz**e≤1000,0 < m \le n \le size0/</m//≤n/≤siz**e,链表中每个节点的值满足 |val| \le 1000∣val∣≤1000

要求:时间复杂度 O(n),空间复杂度 O(n)

进阶:时间复杂度 O(n),空间复杂度 O(1)

示例1

输入:

{1,2,3,4,5},2,4

返回值:

{1,4,3,2,5}

复制

示例2

输入:

{5},1,1

返回值:

{5}

题解

/*
 * function ListNode(x){
 *   this.val = x;
 *   this.next = null;
 * }
 */

/**
  * 
  * @param head ListNode类 
  * @param m int整型 
  * @param n int整型 
  * @return ListNode类
  */
function reverseBetween( head ,  m ,  n ) {
    // write code here
    //如果 m === n,则不需要翻转
    if(m === n){
        return head;
    }
    //如果只有一个节点也不需要翻转
    if(head === null || head.next === null){
        return head;
    }
    //start指向开始翻转节点的前一个节点,即 m -1
    //end 指向n+1
    let cur = head;
    let start = null;
    let end = null;
    //寻找start和end
    for(let i = 1;i <= n; i++){
        if(i === m-1){
            start = cur;
        }
        cur = cur.next;
    }
    end = cur;
    let pre = null
    let next = null
    //如果起始节点不是头节点,说明start有值
    if(m>1){
        cur = start.next;
        while(cur !== end){
            next = cur.next
            cur.next = pre 
            pre = cur 
            cur = next
        }
        start.next.next = end
        start.next = pre
    }else{
        // 起始节点就是头节点,start没有值
        cur = head
        while(cur !== end){
            next = cur.next
            cur.next = pre
            pre = cur
            cur = next
        }
        head.next = end
        head = pre
    }
    return head;
}
module.exports = {
    reverseBetween : reverseBetween
};

思路:

确定边界条件:

  • 如果m和n相等,则不需要翻转,直接返回链表
  • 如果输入的是空链表或只有一个结点,则直接返回链表

第二步:

定义两个指针,pre(指向m-1的结点)=null,end(指向n+1的结点)

cur指向当前结点head;

第三步:遍历,寻找pre和end;将pre指向m-1的结点,end指向n+1的结点

不过会有特殊情况,m=1,pre指向null,n是最后一个结点的话,end指向null

第四步,定义两个指针,pre和end

再遍历一下链表,进行反转,有个判断,当m>1时,说明有值,翻转是局部的。

如果m不>1,那就是从头就开始翻转

牛客–BM64 最小花费爬楼梯

描述

给定一个整数数组 cost,其中 cost[i] 是从楼梯第i 个台阶向上爬需要支付的费用,下标从0开始。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

数据范围:数组长度满足 1≤n≤10^5 ,数组中的值满足1≤cost≤ 10^4

示例1

输入:[2,5,20]
返回值:5
说明:你将从下标为1的台阶开始,支付5 ,向上爬两个台阶,到达楼梯顶部。总花费为5

示例2

输入:[1,100,1,1,1,90,1,1,80,1]
返回值:6
说明:你将从下标为 0 的台阶开始。
	1.支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
	2.支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
	3.支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
	4.支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
	5.支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
	6.支付 1 ,向上爬一个台阶,到达楼梯顶部。
	总花费为 6 。 

请你计算并返回达到楼梯顶部的最低花费。

题解

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param cost int整型一维数组 
 * @return int整型
 */
function minCostClimbingStairs( cost ) {
    // write code here
    let arr=[0,0];
    for(let i=2;i<=cost.length;i++){
        arr[i]=Math.min(arr[i-1]+cost[i-1],arr[i-2]+cost[i-2]);
    }
    return arr[cost.length];
}
module.exports = {
    minCostClimbingStairs : minCostClimbingStairs
};

思路

用了dp动态规划,每跳一次,只会有两个情况,要么是前一级台阶向上一级,要么就是前两级的台阶向上两步,因为在前面的台阶花费我们都得到了,因此每次更新最小值即可,转移方程为: dp[i] = min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2])

返回的是dp数组中最后一个,即cost.length。

复杂度:

  • 时间复杂度O(n)
  • 空间复杂度O(n)

牛客–BM88 判断是否为回文字符串

描述

给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。

字符串回文指该字符串正序与其逆序逐字符一致

数据范围:0<n≤1000000

要求:空间复杂度 O(1),时间复杂度 O*(n)

示例1

输入:"absba"
返回值:true

示例2

输入:"ranko"
返回值:false

示例3

输入:"yamatomaya"
返回值:false

示例4

输入:"a"
返回值:true

题解

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 
 * @param str string字符串 待判断的字符串
 * @return bool布尔型
 */
function judge( str ) {
    // write code here
    let restr = str.split("").reverse().join("");
    if(restr === str){
        return true;
    }
    return false
    //简便写法
    //return str.split("").reverse().join("") === str;
}
module.exports = {
    judge : judge
};

思路

利用js的方法进行反转,再判断。

牛客—BM83 字符串变形

描述

对于一个长度为 n 字符串,我们需要对它做一些变形。

首先这个字符串中包含着一些空格,就像"Hello World"一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,同时反转每个字符的大小写。

比如"Hello World"变形后就变成了"wORLD hELLO"。

数据范围:1≤ n≤10^6,字符串中包括大写英文字母、小写英文字母、空格。

进阶:空间复杂度 O(n) , 时间复杂度 O(n)

输入描述:

给定一个字符串s以及它的长度n(1≤ n≤10^6)

返回值描述:

请返回变形后的字符串。题目保证给定的字符串均由大小写字母和空格构成。

示例1

输入:"This is a sample",16
返回值:"SAMPLE A IS tHIS"

示例2

输入:"nowcoder",8
返回值:"NOWCODER"

示例3

输入:"iOS",3
返回值:"Ios"

题解

function trans(s, n){
        //write code here
    //如果输入的字符串和长度是空的,则返回空字符串     
    if(!s || !n){
        return '';
    }
    //定义一个栈stack
    const stack = [];
    //定义栈的元素     
    let stackEle = '';
    //定义转换后的字符串     
    let transformWord  = '';
    
    //循环更改
    for(let i = 0; i < n; i++){
        //取逐个字符
        const asciiCode = s.charCodeAt(i);
        
        if(asciiCode >= 65 && asciiCode <= 90){
            transformWord += s[i].toLowerCase();
        }else if(asciiCode >= 97 && asciiCode <= 122){
            transformWord += s[i].toUpperCase();
        }else {
            //空格
            const ele = ' ' + transformWord;
            stack.push(ele);
            transformWord = '';
        }
    }
    //当循环结束后,栈里最后一个单词没有入栈,是因为循环结束后,transformWord的值就是第一次出栈的结果
    while(stackEle = stack.pop()){
        transformWord += stackEle;
    }
    
    return transformWord;
}

module.exports = {
    trans : trans
}

思路:

利用栈的特性

  1. 遍历每个字符,并且转换大小写,除空格以外。
  2. 若遍历到空格则把前面遍历的字符视为一个单词,加入栈,并在单词前面拼接一个空格,这样再出栈拼接单词时就有了空格。
  3. 出栈拼接单词,返回最后的结果

复杂度:

  • 时间复杂度O(n)
  • 空间复杂度O(n)

牛客–BM84 最长公共前缀

描述

给你一个大小为 n 的字符串数组 strs ,其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀,返回这个公共前缀。

数据范围:0≤n≤5000,0≤len(strs)≤5000

进阶:空间复杂度 O(n),时间复杂度O(n)

示例1

输入:["abca","abc","abca","abc","abcc"]
返回值:"abc"

示例2

输入:["abc"]
返回值:"abc"

方法一—子串纵向查找

题解
/**
  * 
  * @param strs string字符串一维数组 
  * @return string字符串
  */
function longestCommonPrefix( strs ) {
    // write code here
    //如果数组为空,则返回空值
    if(strs.length === 0){
        return '';
    }
    if(strs.length == 1) return strs[0];
    for(let  i = 0 ;i<strs[0].length;i++){
        for(let j = 1;j<strs.length;j++){
            if(strs[0][i]!==strs[j][i]||i===strs[j].length){
                return strs[0].substr(0,i);
            }
        }
    }
    return strs[0];
}
module.exports = {
    longestCommonPrefix : longestCommonPrefix
};
思路:

纵向遍历将每个字符串分别依次遍历每一列的元素,比较相同列上字符是否相同,若相同则比较下一个子串,若不同则最长公共前缀为上个遍历过的公共前缀。

复杂度分析

时间复杂度O(mn),其中n是字符串的数量,m是字符串数组中的字符串的平均长度。最坏情况下,字符串数组中的每个字符串的每个字符都会被比较一次。

空间复杂度O(1)。额外空间复杂度为常数。

方法二—排序后子串纵向查找

题解:
/**
  * 
  * @param strs string字符串一维数组 
  * @return string字符串
  */
function longestCommonPrefix( strs ) {
    // write code here
    //如果数组为空,则返回空值
    if(strs.length === 0){
        return '';
    }
    if(strs.length == 1) return strs[0];
    let newstr = strs.sort();
    let arrA =newstr[0]; 
    let arrB = newstr[newstr.length-1];
    for(var  i = 0 ;i<arrA.length&&(arrA[i]===arrB[i]);i++);//循环第一个子串的每个字符
    return arrA.substr(0,i);
}
module.exports = {
    longestCommonPrefix : longestCommonPrefix
};
思路:

先将所有子字符串按照字典序的大小排序,现只需要比较字典序最小的子串A与字典序最大的B比较相同部分,得到最长公共前缀就是所有子串的公共前缀。

时间复杂度O(nlogn),其中n是字符串的数量,排序算法时间复杂度O(nlogn)。

空间复杂度O(1)。额外空间复杂度为常数。

牛客-----BM86 大数加法

描述

以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。

数据范围:s.length,t.length ≤ 100000,字符串仅由’0’~‘9’构成

要求:时间复杂度 O(n)

示例1

输入:"1","99"
返回值:"100"
说明:1+99=100 

示例2

输入:"114514",""
返回值:"114514"

题解:

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 计算两个数之和
 * @param s string字符串 表示第一个整数
 * @param t string字符串 表示第二个整数
 * @return string字符串
 */

function solve( s ,  t ) {
    // write code here
    let sp = s.length-1;
    let tp = t.length-1;
    let resArr = [];
    let p = 0;
    let sum = 0;
    while(sp >= 0 || tp >= 0 || p !== 0){
        let sV = sp >= 0 ? s[sp] - 0 : 0;//s[sp]-0 相当于parseInt(s[i]);
        let tV = tp >= 0 ? t[tp] - 0 : 0;
        sum = sV + tV + p;
        resArr.unshift(sum % 10);
        p = sum >= 10 ? 1 : 0;
        sp--;
        tp--;   
    }
    return resArr.join('');
}
module.exports = {
    solve : solve
};

思路

模拟法(双尾指针法)

思路:模拟我们日常加法进位过程,详细过程看代码

时间复杂度O(n),其中 n 为较长字符的长度,遍历字符串

空间复杂度O(1),常数级空间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值