刷题打卡
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
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 ,并有如下功能:
- Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
- get(key):如果关键字 key 存在于缓存中,则返回key对应的value值,否则返回 -1 。
- 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);
*/