牛客网机试题

第一题:反转链表

1.1题目描述

输入一个链表,反转链表后,输出新链表的表头。

输入:

{1,2,3}

返回值:

{3,2,1}

具体如图:

1.2解题思路

 

 需要三个指针:pre,p,q去完成一个头节点插入

1.3代码

java

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head==null){
            return head;
        }
        ListNode p=head;
        ListNode q=p.next;
        head.next=null;
        ListNode pre=null;
        while(q!=null){
            head=q;
            pre=p;
            p=q;
            q=p.next;
            head.next=pre;
        }
        return head;
    }
}

1.4注意知识点

在写代码过程中遇到了如下问题

出现了数组越界,原因是p为空的时候,q=p.next越界

第二题:设计LRU缓存结构

2.1题目描述

设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能

  • set(key, value):将记录(key, value)插入该结构
  • get(key):返回key对应的value值

[要求]

  1. set和get方法的时间复杂度为O(1)
  2. 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
  3. 当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。

若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,输出一个答案

2.2解题思想

模拟整个LRU(最久未使用)过程

创建一个二维数组,模拟一个map(key,value),

输入的[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]]看成二维数组

输出[1,-1],看作一个一维数组。有几个get,这个数组的长度就为多少

 

2.3代码

import java.util.*;


public class Solution {
    /**
     * lru design
     * @param operators int整型二维数组 the ops
     * @param k int整型 the k
     * @return int整型一维数组
     */
    public int[] LRU (int[][] operators, int k) {
        // write code here
        int resultlength=0;
        int r=0;
        //n代表输入了几次set和get的次数和
        int n=operators.length;
        System.out.println(n);
        for(int q=0;q<n;q++){
            if(operators[q][0]==2){
                //有几次get
                resultlength++; 
            }
        }
        System.out.println(resultlength);
       int[] a=new int[resultlength];
        //将key和value看作一个二维数组,2行k列
        int[][] b=new int[2][k];
        for(int i=0;i<n;i++){
            if(operators[i][0]==1){
                for(int j=k-1;j>0;j--){
                    b[0][j]=b[0][j-1];
                    b[1][j]=b[1][j-1];
                }
                b[0][0]=operators[i][1];
                b[1][0]=operators[i][2];
            }else if(operators[i][0]==2)
            {
                //代表get是否找到
                boolean flag=false;
                for(int m=0;m<k;m++){
                    if(b[0][m]==operators[i][1]){
                        flag=true;
                        a[r]=b[1][m];
                        r++;
                        int key=b[0][m];
                        int value=b[1][m];
                        for(int j=m;j>0;j--){
                            b[0][j]=b[0][j-1];
                            b[1][j]=b[1][j-1];
                        }
                        b[0][0]=key;
                        b[1][0]=value;
                    }
                }
                if(!flag){
                    a[r]=-1;
                    r++;
                }
            }
        }
        return a;
    }
}

此代码可以改善

 2.4注意

时间问题,我看到题目,一般是大概有个思路,然后就去敲代码,代码运行不成功,然后就去一行一行的找错,相对来说时间耗费巨大。目前感觉自己没有特别好的办法

第三题:实现二叉树先序,中序和后序遍历

3.1题目描述

分别按照二叉树先序,中序和后序打印所有的节点。

3.2解题思路

使用递归的方法,我们熟悉的二叉树遍历

void PreOrder(root T){
    if(T!=NULL){
        visit(T);
        PreOrder(T->left);
        PreOrder(T->right);
    }
}

void InOrder(root T){
    if(T!=NULL){
        InOrder(T->left);
        visit(T);
        InOrder(T->right);
    }
}

void PostOrder(root T){
    if(T!=NULL){
        PostOrder(T->left);
        PostOrder(T->right);
        visit(T);
    }
}
    

 二叉树的遍历有非递归的解题思路,借助栈来实现,访问根节点压栈

3.3代码实现

使用递归方法实现的java代码

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    List<Integer> pre = new ArrayList<>();
    List<Integer> mid = new ArrayList<>();
    List<Integer> last = new ArrayList<>();
    /**
     * 
     * @param root TreeNode类 the root of binary tree
     * @return int整型二维数组
     */
    public int[][] threeOrders (TreeNode root) {
        // write code here
        preOrder(root);
        InOrder(root);
        PostOrder(root);
        int size=pre.size();
        int[][] result=new int[3][size];
        
        for(int i=0;i<size;i++){
            
            result[0][i]=pre.get(i);
            result[1][i]=mid.get(i);
            result[2][i]=last.get(i);
        }
        return result;
    }
    
    public void preOrder(TreeNode root){
        if(root!=null){
            pre.add(root.val);
            preOrder(root.left);
            preOrder(root.right);
        }
       
    }
    
    public void InOrder(TreeNode root){
        if(root!=null){
            InOrder(root.left);
            mid.add(root.val);
            InOrder(root.right);
        }
    }
    
    public void PostOrder(TreeNode root){
        if(root!=null){
            PostOrder(root.left);
            PostOrder(root.right);
            last.add(root.val);
        }
    }
}

3.4遇到的问题和注意点

我最开始不想使用Java的接口类,准备使用原始数组来实现。

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param root TreeNode类 the root of binary tree
     * @return int整型二维数组
     */
    public int[][] threeOrders (TreeNode root) {
        // write code here
        int[][] result=new int[3][3];
        System.out.println("preOrder----------------");
        preOrder(root,result,-1);
        System.out.println(result[0][1]);
        System.out.println("InOrder----------------");
        InOrder(root,result,-1);
        System.out.println(result);
        System.out.println("PostOrder----------------");
        PostOrder(root,result,-1);
        System.out.println(result);
        return result;
    }
    
    public int[][] preOrder(TreeNode root,int[][] result,int i){
        if(root!=null){
            ++i;
            System.out.println("下标"+i);
            result[0][i]=root.val;
            System.out.println(result[0][i]);
            preOrder(root.left,result,i);
            preOrder(root.right,result,i);
        }
        return result;
    }
    
    public int[][] InOrder(TreeNode root,int[][] result,int i){
        if(root!=null){
            ++i;
            System.out.println("下标"+i);
            InOrder(root.left,result,i);
            result[1][i]=root.val;
            System.out.println(result[1][i]);
            InOrder(root.right,result,i);
        }
        return result;
    }
    
    public int[][] PostOrder(TreeNode root,int[][] result,int i){
        if(root!=null){
            ++i;
            PostOrder(root.left,result,i);
            PostOrder(root.right,result,i);
            result[2][i]=root.val;
            System.out.println(result[2][i]);
        }
        return result;
    }
}

因为涉及到数组的定义时需要确定数组大小,因此不合适

最大的问题是,我的数组下标是乱的,这个设计到递归时执行的速度,需要重新理一遍。

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

可以参考以下链接:

Java ArrayList | 菜鸟教程 (runoob.com)

第四题:寻找第K大

4.1题目描述

给定一个整数数组a,同时给定它的大小n和要找的K(1<=K<=n),请返回第K大的数(包括重复的元素,不用去重),保证答案存在。

4.2解题思路

使用快排的思想,根据先快排,然后取值,在快排的过程边进行判断,会节约时间。

快排的思想:

  • 哨兵为pivoit=a[low],使用两个指针low,high,
  • high从后往前查找,查找第一个小于pivoit的值
  • 将a[low]=a[high]
  • low从前往后查找大于pivoit的值,low指针停在这个位置
  • a[high]=a[low]
  • 直到遍历第一趟(low<high)结束,将a[low]=pivoit

具体过程如图:

其中快排代码如下

有一个数确定最终位置,这个数前面的所有数都比pivot小,后面都比他大
分而治之
void QuickSort(ElemType a[],int low,int high){
    if(low<high){
        ElemType pivotresult=Partition(a,low,high);    
        QuickSort(a,low,pivotresult-1);
        QuickSort(a,pivotresult+1,high);
    }
}

//每一趟排序的代码,执行一次,就有一个数到达最终有序的位置
int Partition(ElemType a[],int low,int high){
    ElemType pivot=a[low];
    while(low<high){
        while(low<high&&a[high]>=pivot)    --high;
        a[low]=a[high];
        while(low<high&&a[low]<=pivot)    ++low;
        a[high]=a[low];
    }
    a[low]=pivot;
    return low;
}
        

       

4.3代码实现

先排序,在查找

import java.util.*;

public class Solution {
    public int findKth(int[] a, int n, int K) {
        // write code here
        //System.out.println(a[n-1]);
        QuickSort(a,0,n-1);
        int flag=n-K;
        int result=a[flag];
        return result;
        
    }
    
    public void QuickSort(int[] a, int low, int high){
        if(low<high){
            int pivotop=Partition(a, low, high);
            QuickSort(a,low,pivotop-1);
            QuickSort(a,pivotop+1,high);
        }
    }
    
    public int Partition(int[] a, int low, int high){
        int pivot=a[low];
        //System.out.println("@@@@@@@@@@@"+pivot);
        while(low<high){
            while(low<high&&a[high]>=pivot){
                --high;
            }
            a[low]=a[high];
            while(low<high&&a[low]<=pivot){
                ++low;
            }
            a[high]=a[low];
        }
        a[low]=pivot;
        return low;
    }
}

修改一下的代码,相对来效率会高一些,特别是数据量较大的时候

import java.util.*;

public class Solution {
    public int findKth(int[] a, int n, int K) {
        // write code here
        //System.out.println(a[n-1]);
        int flag=n-K;
        int result;
        int temp=QuickSort(a,0,n-1,flag);
        if(temp==0){
            result=a[flag];
        }else{
            result=temp;
        }
        
        return result;
        
    }
    
    public int QuickSort(int[] a, int low, int high,int flag){
        if(low<high){
            int pivotop=Partition(a, low, high);
            if(pivotop==flag){
                return a[pivotop];
            }else{
                QuickSort(a,low,pivotop-1,flag);
                QuickSort(a,pivotop+1,high,flag);
            }
         }
        return 0;
    }
    
    public int Partition(int[] a, int low, int high){
        int pivot=a[low];
        //System.out.println("@@@@@@@@@@@"+pivot);
        while(low<high){
            while(low<high&&a[high]>=pivot){
                --high;
            }
            a[low]=a[high];
            while(low<high&&a[low]<=pivot){
                ++low;
            }
            a[high]=a[low];
        }
        a[low]=pivot;
        return low;
    }
}

第五题: 两数之和

5.1题目描述 

给出一个整数数组,请在数组中找出两个加起来等于目标值的数,

你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的

假设给出的数组中只存在唯一解

例如:

给出的数组为 {20, 70, 110, 150},目标值为90
输出 index1=1, index2=2

5.2解题思路

5.2.1暴力枚举

使用两次循环    index1,index2,比较是否等于target

时间复杂度:O(N^2)

空间复杂度:O(1)

import java.util.*;


public class Solution {
    /**
     * 
     * @param numbers int整型一维数组 
     * @param target int整型 
     * @return int整型一维数组
     */
    public int[] twoSum (int[] numbers, int target) {
        // write code here
        int index1,index2;
        int[] a=new int[2];
        for(int i=0;i<numbers.length-1;i++){
            index1=numbers[i];
            for(int j=i+1;j<numbers.length;j++){
                index2=numbers[j];
                if(index1+index2==target){
                    a[0]=i+1;
                    a[1]=j+1;
                    return a;
                }
            }
        }
        return a;
    }
}


 

 5.2.2 hashmap表

以空间换时间

时间复杂度:O(N),其中 N 是数组中的元素数量。对于每一个元素 x,我们可以 O(1) 地寻找 target - x。

空间复杂度:O(N),其中 N 是数组中的元素数量。主要为哈希表的开销。

5.3代码实现

hashmap的代码实现

import java.util.*;


public class Solution {
    /**
     * 
     * @param numbers int整型一维数组 
     * @param target int整型 
     * @return int整型一维数组
     */
    public int[] twoSum (int[] numbers, int target) {
        // write code here
        int len=numbers.length;
        HashMap<Integer,Integer> hashmap=new HashMap<Integer,Integer>(len-1);
        hashmap.put(numbers[0],0);
        for(int i=1;i<=len;i++){
            if(hashmap.containsKey(target-numbers[i])){
                return new int[]{hashmap.get(target-numbers[i])+1,i+1};
            }else{
                hashmap.put(numbers[i],i);
            }
        }
        throw new IllegalArgumentException("no two ");
    }
}

第六题:合并有序链表

6.1题目描述

将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的,且合并后新链表依然有序。

6.2解题思路

我们可以用迭代的方法来实现上述算法。当 l1 和 l2 都不是空链表时,判断 l1 和 l2 哪一个链表的头节点的值更小,将较小值的节点添加到结果里,当一个节点被添加到结果里之后,将对应链表中的节点向后移一位。

6.3代码

public class Solution {
    /**
     * 
     * @param l1 ListNode类 
     * @param l2 ListNode类 
     * @return ListNode类
     */
    public ListNode mergeTwoLists (ListNode l1, ListNode l2) {
        if(l1==null){
            return l2;
        }
        if(l2==null){
            return l1;
        }
        ListNode head=new ListNode(0);
        ListNode q=head;
        while(l1!=null&&l2!=null){
            if(l1.val<=l2.val){
                q.next=l1;
                l1=l1.next;
            }else{
                q.next=l2;
                l2=l2.next;
            }
            q=q.next;
        }
        if(l1!=null){
            q.next=l1;
        }
        if(l2!=null){
            q.next=l2;
        }
        return head.next;    
    }
}

第七题:子数组的最大累加和问题

7.1问题描述

给定一个数组arr,返回子数组的最大累加和

7.2解题思路

Picture1.png

时间复杂度 O(N): 线性遍历数组 nums 即可获得结果,使用 O(N) 时间

 空间复杂度 O(1) : 使用常数大小的额外空间

7.3实现代码

import java.util.*;


public class Solution {
    /**
     * max sum of the subarray
     * @param arr int整型一维数组 the array
     * @return int整型
     */
    public int maxsumofSubarray (int[] arr) {
        // write code here
        int n=arr.length;
        int[] dp=new int[n];
        dp[0]=arr[0];
        int flag=dp[0];
        for(int i=1;i<n;i++){
            if(dp[i-1]<=0){
                dp[i]=arr[i];
            }else{
                dp[i]=dp[i-1]+arr[i];
            }
            if(dp[i]>flag){
                flag=dp[i];
            }
        }
         return flag;
    }
   
}

第八题:反转字符串

8.1题目描述

写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

 8.2解题思路

8.3代码实现

import java.util.*;


public class Solution {
    /**
     * 反转字符串
     * @param str string字符串 
     * @return string字符串
     */
    public String solve (String str) {
        // write code here
        char[] arr=str.toCharArray();
        int len=arr.length;
        for(int i=0;i<len/2;i++){
            char temp=arr[i];
            arr[i]=arr[len-i-1];
            arr[len-i-1]=temp;
        }
        String a=new String(arr);
        return a;
    }
}

 

8.4注意点

想记一下字符串和字符数组之间的各种转换。

字符数组转字符串

char[]   data={'a','b','c'};   
String  s=new   String(data);

字符串转字符数组

char[] arr=str.toCharArray();

list转字符数组

List<String> list = new ArrayList<String>();
list.add("a1");
list.add("a2");
String[] toBeStored = list.toArray(new String[list.size()]);
for(String s : toBeStored) {
System.out.println(s);
} 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值