牛客面试高频算法题js(矩阵元素查找、括号生成、重排链表、有重复项数字的全排列、加起来和为目标值的组合(二))

NC86 矩阵元素查找

描述

已知一个有序矩阵mat,同时给定矩阵的大小nm以及需要查找的元素x,且矩阵的行和列都是从小到大有序的。设计查找算法返回所查找元素的二元数组,代表该元素的行号和列号(均从零开始)。保证元素互异。

数据范围:0 \le n,m \le 10000≤n,m≤1000,矩阵中的任何元素满足 0 < mat_{i,j} \le 10000000<mat**i,j≤1000000

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

示例1

输入:

[[1,2,3],[4,5,6]],2,3,6

返回值:

[1,2]

示例2

输入:

[[1,2,3]],1,3,2

返回值:

[0,1]

方法一:

/**
 * 
 * @param mat int整型二维数组 
 * @param n int整型 
 * @param m int整型 
 * @param x int整型 
 * @return int整型一维数组
 */
function findElement( mat ,  n ,  m ,  x ) {
    // 方法一(暴力)
    let res=[]
    for(let i=0;i<n;i++){
        for(let j=0;j<m;j++){
            if(mat[i][j]==x){
                res.push(i);
                res.push(j);
            }
        }
    }
    return res;
}
module.exports = {
    findElement : findElement
};

方法二:

function findElement( mat ,  n ,  m ,  x ) {
// 方法二(贪心)
//     定位左下角
    let i=n-1,j=0;
//     当坐标在矩阵内部时一直循环
    while(i>=0&&j<m){
//         往上走
        if(mat[i][j]>x){
            i--;
//             往右走
        }else if(mat[i][j]<x){
            j++;
//             找到值退出
        }else{
            break;
        }
    }
    return [i,j];
}
module.exports = {
    findElement : findElement
};

NC26 括号生成

描述

给出n对括号,请编写一个函数来生成所有的由n对括号组成的合法组合。

例如,给出n=3,解集为:

“((()))”, “(()())”, “(())()”, “()()()”, “()(())”

数据范围:0 \le n \le 100≤n≤10

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

示例1

输入:

1

返回值:

["()"]

示例2

输入:

2

返回值:

["(())","()()"]

代码:

/**
  * 
  * @param n int整型 
  * @return string字符串一维数组
  */
function generateParenthesis( n ) {
    let res=[];
    function find(left,right,str){
//         当左括号和右括号的数目都等于n时
        if(left==n&&right==n){
            return res.push(str);
        }
//         使用左括号
        if(left<n){
            find(left+1,right,str+"(")
        }
//         当右括号少于左括号时,使用右括号
        if(right<n&&right<left){
            find(left,right+1,str+")")
        }
    }
    find(0,0,"");
    return res;
}
module.exports = {
    generateParenthesis : generateParenthesis
};

NC2 重排链表

描述

将给定的单链表\ L L: L_0→L_1→…→L_{n-1}→L_ nL0→L1→…→L**n−1→L**n
重新排序为:L_0→L_n →L_1→L_{n-1}→L_2→L_{n-2}→…L0​→L**n​→L1​→L**n−1​→L2​→L**n−2​→…
要求使用原地算法,不能只改变节点内部的值,需要对实际的节点进行交换。

数据范围:链表长度 0 \le n \le 200000≤n≤20000 ,链表中每个节点的值满足 0 \le val \le 10000≤val≤1000

要求:空间复杂度 O(n)O(n) 并在链表上进行操作而不新建链表,时间复杂度 O(n)O(n)

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

示例1

输入:

{1,2,3,4}

返回值:

{1,4,2,3}

说明:

给定head链表1->2->3->4, 重新排列为 1->4->2->3,会取head链表里面的值打印输出    

示例2

输入:

{1,2,3,4,5}

返回值:

{1,5,2,4,3}

说明:

给定head链表1->2->3->4->5, 重新排列为 1->5>2->4->3,会取head链表里面的值打印输出      

示例3

输入:

{}

返回值:

{}

代码:

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

/**
 * 
 * @param head ListNode类 
 * @return void
 */
function reorderList( head ) {
  
//    方法一
//     如果链表为空或者只有一个值返回空
      if(head==null||head.next==null){
        return head
    }
//     p用于遍历链表
    let p=head;
//     p2用于存储链表后半部分的值
    let p2=[]; 
    let count=0,sum=0;
//     计算链表长度
    while(p){
        p2.push(p.val)
        p=p.next;
        count++;
    }
    p=head;
    sum=0;
//     截取前半部分链表
     while(sum<count/2-1){
        p=p.next;
        sum++;
    }
    p.next=null;
//     在前半部分链表中间隔插入p2弹出的节点
    p=head;
    let cur;
    let node;
    for(let i=1;i<=count/2;i++){  
//         node新建一个节点存储p2尾部弹出的值
           node=new ListNode(p2.pop());
//         保存p后半部分的值
           cur=p.next;
//         在head中插入新节点
           p.next=node;
//         让head重新指向暂存在cur的后半部分
           p.next.next=cur;
//         让p后移两个节点
           p=p.next.next;
    }
    
    return head;
}
module.exports = {
    reorderList : reorderList
};

NC42 有重复项数字的全排列

描述

给出一组可能包含重复项的数字,返回该组数字的所有排列。结果以字典序升序排列。

数据范围: 0 < n \le 80<n≤8 ,数组中的值满足 -1 \le val \le 5−1≤val≤5

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

示例1

输入:

[1,1,2]

返回值:

[[1,1,2],[1,2,1],[2,1,1]]

示例2

输入:

[0,1]

返回值:

[[0,1],[1,0]]

代码:

/**
 * 
 * @param num int整型一维数组 
 * @return int整型二维数组
 */
function permuteUnique( num ) {
    // write code here
    let res=[];
    let path=[];
    let vis=new Array(num.length).fill(false);
    num.sort((a,b)=>{
        return a-b;
    })
    
    function dfs(curr,vis){
//         临时数组加满,存入res
        if(curr.length==num.length){
           res.push([...curr]);
            return;
        }
        for(let i=0;i<num.length;i++){
//          如果当前元素与同一层的前一个相同并且num[i-1]已经使用过了
            if(num[i]==num[i-1]&&!vis[i-1])
                continue;
//             如果当前元素未被加入
           if(!vis[i]){
//                加入当前元素
               curr.push(num[i]);
//                标记当前元素被加入
               vis[i]=true;
//               递归
               dfs(curr,vis);
//                回溯
               curr.pop();
//                标记弹出元素未被加入
                vis[i]=false;
           }
        }

    }
    dfs([],vis);
    
//     res里的路径去重
//     let obj={}
//     res.forEach(item=>obj[item]=item)
//     res=Object.values(obj);
    
    return res
}
module.exports = {
    permuteUnique : permuteUnique
};

NC46 加起来和为目标值的组合(二)

描述

给出一组候选数 c 和一个目标数 t ,找出候选数中起来和等于 t 的所有组合。

c 中的每个数字在一个组合中只能使用一次。

注意:

\1. 题目中所有的数字(包括目标数 t )都是正整数
\2. 组合中的数字 ( a_1, a_2, … , a_ka1​,a2​,…,a**k​ ) 要按非递减排序 ( a_1 \leq a_2 \leq … \leq a_ka1​≤a2​≤…≤a**k​ ).
\3. 结果中不能包含重复的组合
\4. 组合之间的排序按照索引从小到大依次比较,小的排在前面,如果索引相同的情况下数值相同,则比较下一个索引。

数据范围: 1 \le n \le 701≤n≤70 ,1 \le target \le 1001≤targe**t≤100 , 1 \le C_i \le 501≤C**i≤50

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

示例1

输入:

[100,10,20,70,60,10,50],80

返回值:

[[10,10,60],[10,20,50],[10,70],[20,60]]

说明:

给定的候选数集是[100,10,20,70,60,10,50],目标数是80        

示例2

输入:

[2],1

返回值:

[]

代码:

/**
 * 
 * @param num int整型一维数组 
 * @param target int整型 
 * @return int整型二维数组
 */
function combinationSum2( num,target) {
    let res=[];
    let vis=new Array(num.length).fill(false);
//     对数组排序
    num.sort((a,b)=> a-b)
//     深度搜索
    function dfs(ans,target,begin ){
//         如果当前值为0,则将答案存入res中
        if(target==0){
            res.push([...ans]);
        }
//         当当前值小于0则退出
        if(target<0){
            return ;
        }
//         从begin开始遍历数组
        for(let i=begin;i<num.length;i++){
//             如果当前值与前一个值相同并且当前值大于起始值
            if(num[i]==num[i-1]&&i>begin){
                continue;
            }
              ans.push(num[i]);
//             从下一个位置开始递归
              dfs(ans,target-num[i],i+1);
//             恢复数组
              ans.pop();
        }
    }
    dfs([],target,0)
    return res;
}
module.exports = {
    combinationSum2 : combinationSum2
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值