刷题打卡第一天

刷题打卡

2022-11-17

牛客-面试高频榜单

2 简单 3 中等 1困难

78 反转链表

简单

题目

给定一个单链表的头结点p Head(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围: 0≤n≤1000

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

如当输入链表{1,2,3}时,

经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

示例1

输入:

{1,2,3}

返回值:

{3,2,1}

示例2

输入:

{}

返回值:

{}

说明:

空链表则输出空               

题解

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

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur  = head;
        ListNode next;
		//关键
        while(cur!=null){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
		//注意
        return pre;
    }
}

140 排序

题解

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 将给定数组排序
     * @param arr int整型一维数组 待排序的数组
     * @return int整型一维数组
     */
    public int[] MySort (int[] arr) {
        // write code here
        // 解法1:调用库函数Arrays.sort
        /*
        Arrays.sort(arr);
        return arr;
        */

        // 解法2:冒泡排序bubbleSort
       //return bubbleSort(arr);

       //解法3:快速排序quickSort
        //quickSort(arr , 0 , arr.length-1 );
        //return arr;
		
        //解法4:选择排序selectSort
        //return selectSort(arr);
        
        //解法5:插入排序insertSort
        return insertSort(arr);
        
        //解法6:归并排序mergeSort
        //mergeSort(arr,0,arr.length-1);
        //return arr;

        //解法7:堆排序heapSort
       //heapSort(arr);
       //return arr;
    }

    // 解法2:冒泡排序bubbleSort
    public int[] bubbleSort(int[] arr){
        if(arr.length<2){
            return arr;
        }
        //升序
        //相邻的两两比较,把大的沉在最底下
        for(int i = 0 ;i<arr.length-1 ;i++){
            for(int j = 0 ; j<arr.length-i-1 ;j++){
                if( arr[j] > arr[j+1]){
                    swap(arr,j,j+1);
                }
            }
        }
        return arr;
    }

    //解法3:快速排序quickSort
    public void quickSort(int[] arr,int left ,int right){
        if(left < right){
            int pos = part(arr,left,right);
            QuickSort(arr,pos+1,right);
            QuickSort(arr,left,pos-1);
        }
        
    }
    public int part(int[] arr ,int left ,int right){
        int first = arr[left];
       
        while(left < right){
            while(left<right && arr[left]<=first){
                left++;
            }
            swap(arr,left,right);
            while(left<right && arr[right]>=first){
                right--;
            }
            swap(arr,left,right);

        }
        return  left;
    }

    //解法4:选择排序selectSort
    public int[] selectSort(int[] arr){
	//从无序区间不断挑选出最小值,挑选 n-1 次
    for (int i = 0; i < arr.length - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < arr.length; j++) {
        	//更换最小值下标
            minIndex = arr[minIndex] < arr[j] ? minIndex : j;
        }
        //交换最小值与无序区间第一个元素
        swap(arr,i,minIndex)
    }
}

    //解法5:插入排序insertSort
    public int[]  insertSort(int[] arr){
        for (int i = 1; i < arr.length; i++) {
            int insertValue = arr[i];
            int j = i - 1;
            //从右向左比较元素的同时,进行元素复制
            for(; j >=0 && insertValue < arr[j]; j--){
                arr[j+1] = arr[j];
            }
            //insertValue的值插入适当位置
            arr[j+1] = insertValue;
        }
	}

    
    //解法6:归并排序MergeSort
    public void mergeSort(int[] arr,int l,int r){
        if(l==r){
            return;
        }
        int mid = l+((r-l)>>1); //中点位置,即(l+r)/2
        mergeSort(arr,l,mid);
        mergeSort(arr,mid+1,r);
        merge(arr,l,mid,r);
    }
 
    public void merge(int[] arr,int l,int mid,int r){
        int [] help= new int[r-l+1];    //辅助数组
        int i=0;
        int p1=l; //左半数组的下标
        int p2=mid+1; //右半数组的下标
    
        //判断是否越界
        while(p1<=mid && p2<=r){
            help[i++]=arr[p1]<arr[p2] ? arr[p1++] : arr[p2++];
        }
        //p1没有越界,说明p2越界了,将左边剩余元素拷贝到辅助数组
        while(p1<=mid){
            help[i++]=arr[p1++];
        }
        //p2没有越界,说明p1越界了
        while(p2<=r){
            help[i++]=arr[p2++];
        }
        //将辅助数组元素拷贝会原数组
        for(i=0;i<help.length;i++){
            arr[l+i]=help[i];
        }
    }

    //解法7:堆排序HeapSort
   public static void heapSort(int[] arr){
       if(arr == null || arr.length<2){
           return;
       }
       for(int i=0;i<arr.length;i++){
           heapInsert(arr,i); //构造完全二叉树
       }
       int size = arr.length;
       swap2(arr,0,--size);
       while(size>0){
           heapify(arr,0,size);// 最后一个数与根交换
           swap2(arr,0,--size);
       }

   }
   //判断该结点与父结点的大小,大结点一直往,建立大根堆
   public static void heapInsert(int[] arr,int index){
       while(arr[index]>arr[(index-1)/2]){
           swap2(arr,index,(index-1)/2);
           index=(index-1)/2;
       }
   }

   //一个值变小往下沉的过程
   public static void heapify(int[] arr,int index,int size){
       int left=index*2+1;
       while(left<size){
           int largest = left + 1 < size && arr[left+1] > arr[left] ? left+1 : left;
           largest = arr[largest] > arr[index] ? largest :index;
           if(largest==index){
               break;
           }
           swap2(arr,largest,index);
           index=largest;
           left=index*2 +1;

       }
   }

   //交换函数
   public static void swap2(int[] arr, int i, int j){
       int tmp;
       tmp=arr[i];
       arr[i]=arr[j];
       arr[j]=tmp;
   }


    public void swap(int[] arr ,int i ,int j){
        int temp = arr[i] ;
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

tips

img

45 二叉树先序,中序和后序遍历

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) {
       //三个集合,分别存储三种遍历结果
        List<Integer> list1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();
        List<Integer> list3 = new ArrayList<>();

        //调用函数计算遍历结果
        preOrder(root, list1);
        inOrder(root, list2);
        postOrder(root, list3);

        //存放结果集
        int[][] res = new int[3][list1.size()];
        for(int i = 0; i < list1.size(); i++){
            res[0][i] = list1.get(i);
            res[1][i] = list2.get(i);
            res[2][i] = list3.get(i);

        }
        //答案返回
        return res;
    }
    // 先序遍历函数
    public void preOrder(TreeNode root, List<Integer> list){
        //特判
        if(root == null){
            return;
        }
        //对左右子树进行递归的遍历
        list.add(root.val);
        preOrder(root.left, list);
        preOrder(root.right, list);
    }

    // 中序遍历函数
    public void inOrder(TreeNode root, List<Integer> list){
        //特判
        if(root == null){
            return;
        }
       //递归调用:对左右子树进行递归的遍历
        inOrder(root.left, list);
        list.add(root.val);
        inOrder(root.right, list);
    }

    // 后序遍历函数
    public void postOrder(TreeNode root, List<Integer> list){
        if(root == null){
            return;
        }
        //递归调用:对左右子树进行递归的遍历
        postOrder(root.left, list);
        postOrder(root.right, list);
        list.add(root.val);
    }

}

15 二叉树层序遍历

import java.util.*;

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

public class Solution {
    /**
     * 
     * @param root TreeNode类 
     * @return int整型ArrayList<ArrayList<>>
     */
    public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
        
        // write code here
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        if(root==null) return res;
        ArrayList<Integer> temp = new ArrayList<Integer>();
        
        ArrayList<TreeNode> list = new ArrayList<TreeNode>();
        list.add(root);

        while(!list.isEmpty()){
            int count = list.size();
            temp = new ArrayList<Integer>();
            for(int i = 0 ; i<count ;i++){
                TreeNode t = list.get(0);
                list.remove(0);
                temp.add(t.val);
                if(t.left!=null) list.add(t.left);
                if(t.right!=null) list.add(t.right);
            }
            res.add(temp);
        }

        return res;
        
    }
}

119 最小的K个数

题目

给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。

题解

    import java.util.*;
    public class Solution{
    public ArrayList<Integer> GetLeastNumbers_Solution(int[] input, int k) {
        ArrayList<Integer> res = new ArrayList<>(k);
        //根据题意要求,如果K>数组的长度,返回一个空的数组
        if (k > input.length || k == 0)
            return res;
        quickSort(input, res, k, 0, input.length - 1);
        return res;
    }

    private void quickSort(int[] input, ArrayList<Integer> res, int k, int left, int right) {
        //快排的实现方式有多种,我们选择了其中的一种
        int start = left;
        int end = right;
        while (left < right) {
            while (left < right && input[right] >= input[start]) {
                right--;
            }
            while (left < right && input[left] <= input[start]) {
                left++;
            }
            swap(input, left, right);
        }
        swap(input, left, start);
        //注意这里,start是数组中元素的下标。在start之前的元素都是比start指向的元素小,
        //后面的都是比他大。如果k==start,正好start之前的k个元素是我们要找的,也就是
        //数组中最小的k个,如果k>start,说明前k个元素不够,我们还要往后再找找。如果
        //k<start,说明前k个足够了,我们只需要在start之前找k个即可。
        if (left > k) {
            quickSort(input, res, k, start, left - 1);
        } else if (left < k) {
            quickSort(input, res, k, left + 1, end);
        } else {
            //取前面的k个即可
            for (int m = 0; m < k; ++m) {
                res.add(input[m]);
            }
        }
    }

    private void swap(int[] arr, int i, int j) {
        if (i == j)
            return;
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    }

93 设计LRU缓存结构

题目

设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能:

  1. Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
  2. get(key):如果关键字 key 存在于缓存中,则返回key对应的value值,否则返回 -1 。
  3. set(key, value):将记录(key, value)插入该结构,如果关键字 key 已经存在,则变更其数据值 value,如果不存在,则向缓存中插入该组 key-value ,如果key-value的数量超过capacity,弹出最久未使用的key-value

提示:
1.某个key的set或get操作一旦发生,则认为这个key的记录成了最常使用的,然后都会刷新缓存。
2.当缓存的大小超过capacity时,移除最不经常使用的记录。
3.返回的value都以字符串形式表达,如果是set,则会输出"null"来表示(不需要用户返回,系统会自动输出),方便观察
4.函数set和get必须以O(1)的方式运行
5.为了方便区分缓存里key与value,下面说明的缓存里key用""号包裹

题解

import java.util.*;

public class Solution {
    private int capacity;
    private Map<Integer, Node> map;
    private Node head;
    private Node tail;
    private int used;
    
    class Node {
        int key;
        int value;
        Node prev;
        Node next;
                
        Node(int key, int value, Node prev, Node next) {
            this.key = key;
            this.value = value;
            this.prev = prev;
            this.next = next;
        }
    }
    
    public Solution(int capacity) {
         // write code here
        this.capacity = capacity;
        this.map = new HashMap<>();
        this.used = 0;
    }

    public int get(int key) {
         // write code here
        if (!map.containsKey(key)) {
            return -1;
        }

        makeRecently(key);
        
        return map.get(key).value;
    }

    public void set(int key, int value) {
         // 如果 key 已存在,直接修改值,再移到链表头部
        if (map.containsKey(key)) {
            map.get(key).value = value;
            makeRecently(key);
            return;
        }
        
        // 如果达到容量上限,就要移除尾部节点,注意 HashMap 要 remove!!!
        if (used == capacity) {
            map.remove(tail.key);
            tail = tail.prev;
            tail.next = null;
            used--;
        }
        // 头节点为空,单独处理
        if (head == null) {
            head = new Node(key, value, null, null);
            tail = head;
        }
        else {
            Node t = new Node(key, value, null, head);
            head.prev = t;
            head = t;
        }
        map.put(key, head);
        
        used++;
    }
    
        // 把 key 对应的节点移到链表头部
    private void makeRecently(int key) {
        Node t = map.get(key);
        if (t != head) {
            if (t == tail) {
                tail = tail.prev;
                tail.next = null;
            }
            else {
                t.prev.next = t.next;
                t.next.prev = t.prev;
            }
            
            t.prev = null;
            t.next = head;
            head.prev = t;
            head = t;
        }
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution solution = new Solution(capacity);
 * int output = solution.get(key);
 * solution.set(key,value);
 */

Node t = map.get(key);
if (t != head) {
if (t == tail) {
tail = tail.prev;
tail.next = null;
}
else {
t.prev.next = t.next;
t.next.prev = t.prev;
}

        t.prev = null;
        t.next = head;
        head.prev = t;
        head = t;
    }
}

}

/**

  • Your Solution object will be instantiated and called as such:
  • Solution solution = new Solution(capacity);
  • int output = solution.get(key);
  • solution.set(key,value);
    */

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值