第一章
电话面试要尽可能形象化的语言把细节说清楚
千万不要不懂装懂,这是面试大忌,大胆多提问 直到弄清楚面试官意图
视频面试:良好的代码命名和缩进对齐习惯,能够进行单元测试,测试在前开发在后
碰到有问题了,就设置断电,单步追踪,查看内存,分析调用栈
现场面试:准备好向面试官提问的 问题
面试分为 行为面试 技术面试和应聘者提问
行为面试:自我介绍,项目经验。用star模型描述自己经历的项目
Situation Task Action Result
不要用负责这么重的字眼
做软件开发的,可以写基于什么工具在哪个平台下应用了什么样的技术
你在项目中碰到的最大的问题是什么,从项目中你学到了什么,与其他团队成员有什么冲突。
突出自己完成的工作和取得的成绩
了解 属于上过课看过书 没有关系的公司就不要加了解了
熟悉 通过查阅相关文档可以独立解决大部分问题
精通 得心应手 ,别人请教我们能够解决
为什么跳槽 工作了一段时间 没有了激情,找一份更有挑战的工作。
技术面试:
一般五个方面,扎实的基础知识,能写高质量的代码,分析问题的思路清晰,优化时间效率和空间效率。
遇到复杂的问题,应聘者可以通过画图,举具体例子分析 和 分解复杂问题等方法先厘清思路然后动手编程。不断优化时间效率和空间效率,力求找到最优的解法。
什么是扎实的基本功: 编程语言 ,数据结构和算法
数据结构:链表,树,栈,队列和哈希表
链表和二叉树问的最多
链表的插入和删除节点了如指掌,对二叉树的各种遍历方法循环和递归方法烂熟于胸。
重点掌握二分查找,归并排序和快速查找
要求高一点就是动态规划和贪心算法
高质量的代码
边界条件,比如把字符串变成数字里面,字符串中有非数字字符和正负号,考虑最大的正整数和负整数以及溢出。
面试的时候要有鲁棒型,怎么做呢,动手之前想好测试用例。
清晰的思路:举几个简单的具体例子让自己理解问题
用图形表示抽象的数据结构,很多基于递归的思路,包括分治法和动态规划,把复杂的问题分解成一个多个问题。
总结:画图能使抽象问题形象化,举例使抽象问题具体化,分解使复杂问题简单化。
除了展示自己技术功底还有自己的软实力,沟通能力和学习能力
知识迁移的能力
面试前做足功课,到网上搜集一些相关的信息,对公司成立时间,主要业务,职位要求了然于胸
第二章
数组可以说是最简单的一种数据结构,它占据连续的内存并按照顺序存储数据。可以在O(1)时间读写任何元素,时间效率很高。也可以变成哈希表,形成“键值-值”配对
为了解决数组空间效率不高的问题,设计了动态数组,就像C++ STL中的vector
数组中重复的数字
方法一:
直接两重循环,用==找到相同 的数
方法二:
建立哈希表,判断这个数字是不是有过了。时间复杂度时O(n),空间复杂度O(n)
function duplicate(numbers, duplication)
{
if(numbers.length ==1) return false;
if(numbers == null) return false;
let hash = Array(numbers.length);
for (let i = 0; i< numbers.length; i++){
if(hash[numbers[i]]){
duplicationp[0] = numbers[i];
return true;
}else{
hash[numbers[i]] = numbers[i];
}
}
return false;
}
方法
方法三:
先排序,排序一个n的数组要O(nlog(n))的时间,排序后就能找到重复的数组。
方法四:
function duplicate(numbers, duplication)
{
if(numbers == null) return false;
if(numbers.length <=1) return false;
for(let i = 0; i<numbers.length; i++){
while(numbers[i]! = i){
if(numbers[i] == numbers[numbers[i]]){
duplication[0] = numbers[i];
return true;
}
let temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
return false;
}
交换法
二维数组中的查找
边缘检测法,选择右上角或者左下角与target比较
function Find(target, array)
{
let rows = array.length;
let columns = array[0].length;
for(let row = 0, column = columns-1;row<rows && column>=0;){
if(array[row][column] > target){
column--;
}
else if(array[row][column] < target){
row ++;
}else{
return true;
}
}
return false;
}
面试题 5 替换空格
function replaceSpace(str)
{
return str.replace(/\s/g,"%20");
}
或者
function replaceSpace(str)
{
let arr = new Array();
arr = str.split(" ");
let output = arr[0];
for (let i = 1;i<arr.length;i++){
output = output + "%20"+arr[i];
}
return output;
}
剑指offer上的方法,未完成
function replaceSpace(str){
if(str.length<=0) return;
let originalLength = str.length;
let numberOfBlank = 0;
for(let i = 0; i<str.length;i++){
if(str[i] == " ") numberOfBlank++;
}
let newLength = originalLength + numberOfBlank*2;
let indexOfOriginal = originalLength;
let indexOfNew = newLength;
while(indexOfOriginal>=0 && indexOfNew > indexOfOriginal){
if(str[indexOfOriginal] == " "){
str[indexOfNew--] = "0";
str[indexOfNew--] = "2";
str[indexOfNew--] = "%";
}
else{
str[indexOfNew--] = str[indexOfOriginal];
}
--indexOfOriginal;
}
return str;
}
面试6 从尾到头打印链表
前清摘要:
链表是一种动态数据结构,创建链表时,无须知道链表长度,插入一个节点时,只需要为新节点分配内存。每添加一个节点分配一次内存,由于没有闲置内存,链表空间效率比数组高。
链表遍历一次就是O(n),数组是O(1)
\\javascript
function printListFromTailToHead(head)
{
let arr = new Array();
let tmp = head;
while(tmp){
arr.push(tmp.val);
tmp = tmp.next;
}
let output = arr.reverse();
return output;
}
使用java 递归处理
import java.util.ArrayList;
public class Solution {
ArrayList<Integer> mylist = new ArrayList<Integer>();
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
if(listNode!= null){
printListFromTailToHead(listNode.next);
mylist.add(listNode.val);
}
return mylist;
}
}
使用java stack处理
/**
* public class ListNode {
* int val;
* ListNode next = null;
*
* ListNode(int val) {
* this.val = val;
* }
* }
*
*/
import java.util.Stack;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> mystack = new Stack<Integer>();
while(listNode != null){
mystack.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> mylist = new ArrayList<Integer>();
while(!mystack.isEmpty()){
mylist.add(mystack.pop());
}
return mylist;
}
}
面试题7 重建二叉树
前清摘要:
树的父节点和子节点之间用指针连接。
二叉树是树的一种特殊结构,在二叉树中每个节点最多只有两个子节点。
前序遍历:先访问根节点,再访问左子节点,最后访问右子节点。
中序遍历:先访问左子节点,再访问根节点,最后访问右子节点。
后序遍历:先访问左子节点,再访问右子节点,最后访问根节点。
二叉搜索树,左节点总是小于等于根节点,右节点总是大于或者等于根节点。平均在O(logn)时间内
二叉树的特例是堆和红黑树,堆分最大堆和最小堆,需要快速找到最大最小值的就用堆来解决。
红黑树把树中节点定义为红黑两色,并通过规则确保,根节点到叶节点最长路径长度不超过最短路径两倍。
javascript第一种方法
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function reConstructBinaryTree(pre, vin)
{
if(pre.length<=0 || vin.length<=0) return null;
let center = vin.indexOf(pre[0]);
let left = vin.slice(0,center);//中序左子树
let right = vin.slice(center+1);//中序右子树
return{
val:pre[0],
left:reConstructBinaryTree(pre.slice(1,center+1), left),
right:reConstructBinaryTree(pre.slice(center+1), right)
};
}
java解法
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root = createTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
private TreeNode createTree(int []pre,int startpre,int endpre,int []in,int startvin,int endvin){
if(startpre>endpre||startvin>endvin)
return null;
TreeNode root = new TreeNode(pre[startpre]);
for( int i=startvin; i<=endvin;i++){
if(in[i]==pre[startpre]){
root.left = createTree(pre,startpre+1,startpre+i-startvin,in,startvin,i-1);
root.right = createTree(pre,i-startvin+startpre+1,endpre,in,i+1,endvin);
break;
}
}
return root;
}
}
面试题8 二叉树的下一个节点
/*function TreeLinkNode(x){
this.val = x;
this.left = null;
this.right = null;
this.next = null;
}*/
function GetNext(pNode)
{
// write code here
let pnext = null;
let pparent = pNode.next;
if(!pNode)return null
if(pNode.right!=null){
pnext = pNode.right;
while(pnext.left){
pnext = pnext.left;
}
}else{
pnext = pNode.next;
if(pNode.next && pNode.next.right== pNode){
while(pnext.next && pnext.next.right==pnext){
pnext = pnext.next;
}
if(pnext.next!=null){
pnext = pnext.next;
}else{
pnext = null;
}
}
}
return pnext;
}
java解法
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public TreeLinkNode GetNext(TreeLinkNode pNode)
{
TreeLinkNode pnext = null;
if(pNode==null){
return null;
}
if(pNode.right!=null){
pnext = pNode.right;
while(pnext.left!=null){
pnext = pnext.left;
}
}else{
pnext = pNode.next;
if(pnext!=null && pnext.right==pNode){
while(pnext.next!=null && pnext.next.right==pNode){
pnext = pnext.next;
}
if(pnext.next==null){
pnext = null;
}else{
pnext= pnext.next;
}
}
}
return pnext;
}
}```
## 面试题9,用两个栈实现队列
前清摘要:栈是一个不考虑排序的数据结构,需要O(n)时间才能找到最大和最小的元素
栈先进后出
队列先进先出
javascript实现方法
```javascript
var stack1 = [];
var stack2 = [];
function push(node)
{
stack1.push(node);
}
function pop()
{
if(stack2.length==0){
if(stack1.length==0){
return null;
}else{
for(var i=0;i<stack1.length;i++){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}else{
return stack2.pop();
}
}
java解法
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
if(stack2.empty()){
if(stack1.empty()){
throw new RuntimeException("Queue is empty!");
}else{
while(!stack1.empty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}else{
return stack2.pop();
}
}
}
面试题10 斐波那契数列
function Fibonacci(n)
{
if(n < 2){
return n;
}else{
let f0 = 0;
let f1 = 1
for(let i=2; i<=n;i++){
f2 = f1+f0;
f0 = f1;
f1 = f2;
}
return f2;
}
}
十分精妙的C语言解法
class Solution {
public:
int Fibonacci(int n) {
int f = 0, g = 1;
while(n--) {
g += f;
f = g - f;
}
return f;
}
};
青蛙跳台阶和21格子覆盖28都是斐波那契数列
二分法java
import java.util.*;
public class BinarySearch {
public int getPos(int[] A, int n, int val) {
// write code here
if(n <= 0 || A == null) return -1;
int start = 0;
int end = n-1;
int mid = 0;
while(end>start){
mid = (end+start)/2;
if(A[mid] == val){
end = mid;
}else if(A[mid] > val){
end = mid-1;
}else{
start = mid+1;
}
}
if(A[start] == val) return start;
return -1;
}
}
java实现快排
public class fastsort{
public static void main(String[] args) {
int []arr = {3,4,5,6,1,3,6,7,2,3,5,3,3,1,4,5,34,21,2};
quicksort(arr);
for (int i = 0 ;i<arr.length;i++){
System.out.print(arr[i]+",");
}
}
private static void quicksort(int []arr){
qsort(arr, 0, arr.length-1);
}
private static void qsort(int []arr, int left, int right){
if(arr == null || arr.length<=0 || left>=right) return;
int mid = partition(arr, left ,right);
qsort(arr, left ,mid-1);
qsort(arr, mid+1, right);
}
private static int partition(int []arr, int left, int right){
int privot= arr[left];
while(left<right){
while(left<right && arr[right] >= privot){
right--;
}
arr[left] = arr[right];
while(left<right && arr[left] <= privot){
left++;
}
arr[right] = arr[left];
}
arr[left] = privot;
return left;
}
}
面试题11:旋转数组的最小数字
时间太慢
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int left = 0;
int right = array.length-1;
int index = left;
while(left<right){
if((right-left) == 1){
index = right;
break;
}else{
index = (left+right)/2;
if(array[index]>=array[left]){
left = index;
}
if(array[index]<=array[right]){
right = index;
}
}
}
return array[index];
}
}
java 二分法快一点
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
int low = 0;
int high = array.length-1;
while(low<high){
int mid = low+(high - low)/2;
if(array[mid]>array[high]){
low = mid + 1;
}else if(array[mid]==array[high]){
high = high -1;
}else if(array[mid]<array[high]){
high = mid;
}
}
return array[low];
}
}
面试题12:矩阵中的路径
// 回溯
// 基本思想:
// 0.根据给定数组,初始化一个标志位数组,初始化为false,表示未走过,true表示已经走过,不能走第二次
// 1.根据行数和列数,遍历数组,先找到一个与str字符串的第一个元素相匹配的矩阵元素,进入judge
// 2.根据i和j先确定一维数组的位置,因为给定的matrix是一个一维数组
// 3.确定递归终止条件:越界,当前找到的矩阵值不等于数组对应位置的值,已经走过的,这三类情况,都直接false,说明这条路不通
// 4.若k,就是待判定的字符串str的索引已经判断到了最后一位,此时说明是匹配成功的
// 5.下面就是本题的精髓,递归不断地寻找周围四个格子是否符合条件,只要有一个格子符合条件,就继续再找这个符合条件的格子的四周是否存在符合条件的格子,直到k到达末尾或者不满足递归条件就停止。
// 6.走到这一步,说明本次是不成功的,我们要还原一下标志位数组index处的标志位,进入下一轮的判断。
public class square {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
{
//标志位,初始化为false
boolean[] flag = new boolean[matrix.length];
for(int i=0;i<rows;i++){
for(int j=0;j<cols;j++){
//循环遍历二维数组,找到起点等于str第一个元素的值,再递归判断四周是否有符合条件的----回溯法
if(judge(matrix,i,j,rows,cols,flag,str,0)){
return true;
}
}
}
return false;
}
//judge(初始矩阵,索引行坐标i,索引纵坐标j,矩阵行数,矩阵列数,待判断的字符串,字符串索引初始为0即先判断字符串的第一位)
private boolean judge(char[] matrix,int i,int j,int rows,int cols,boolean[] flag,char[] str,int k){
//先根据i和j计算匹配的第一个元素转为一维数组的位置
int index = i*cols+j;
//递归终止条件
if(i<0 || j<0 || i>=rows || j>=cols || matrix[index] != str[k] || flag[index] == true) //matrix[index] != str[k]当前找到的矩阵值不等于数组对应位置的值,flag[index] == true已经走过的
return false;
//若k已经到达str末尾了,说明之前的都已经匹配成功了,直接返回true即可
if(k == str.length-1)
return true;
//要走的第一个位置置为true,表示已经走过了,主程序进入这里终于true了
flag[index] = true;
//回溯,递归寻找,每次找到了就给k加一,找不到,还原,假设找到了,继续进入下一个judge递归,
if(judge(matrix,i-1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i+1,j,rows,cols,flag,str,k+1) ||
judge(matrix,i,j-1,rows,cols,flag,str,k+1) ||
judge(matrix,i,j+1,rows,cols,flag,str,k+1) )
{
return true;
}
//走到这,说明这一条路不通,还原,再试其他的路径
flag[index] = false;
return false;
}
}
javascript解法
function hasPath(matrix, rows, cols, path)
{
let lenOfMatrix = matrix.length;
let flag = new Array(lenOfMatrix);
for(let i=0;i<rows;i++){
for(let j=0;j<cols;j++){
if(judge(matrix, i , j, rows, cols, flag, path, 0))
return true;
}
}
return false;
}
function judge(matrix, i, j, rows, cols, flag, path, k){
let index = i * cols + j;
if( i<0 || j<0 || i>=rows || j>=cols || matrix[index]!= path[k] || flag[index]==true){
return false;
}
flag[index] = true;
if(k == path.length-1){
return true;
}
if(judge(matrix, i+1, j, rows, cols, flag, path, k+1)||
judge(matrix, i-1, j, rows, cols, flag, path, k+1)||
judge(matrix, i, j+1, rows, cols, flag, path, k+1)||
judge(matrix, i, j-1, rows, cols, flag, path, k+1)){
return true;
}
flag[index] = false;
return false;
}
面试题13 机器人运动范围
//回溯法,每到一个点继续判定它周围4个点满不满足条件
public class Solution {
public int movingCount(int threshold, int rows, int cols)
{
if(threshold<=0|| rows<=0 ||cols<=0){
return 0;
}
boolean[] visited = new boolean[rows*cols];
for(int i=0;i<visited.length;i++){
visited[i] = false;
}
int output = countmovement(threshold, rows, cols, 0, 0, visited);
return output;
}
private static int countmovement(int threshold, int rows, int cols, int row, int col,boolean[] visited){
int index = row*cols+col;
int count = 0;
if(check(threshold, rows, cols, row, col, visited)){
visited[index] = true;
count = 1+countmovement(threshold, rows, cols, row+1, col, visited)+
countmovement(threshold, rows, cols, row-1, col, visited)+
countmovement(threshold, rows, cols, row, col+1, visited)+
countmovement(threshold, rows, cols, row, col-1, visited);
}
return count;
}
private static boolean check(int threshold, int rows, int cols,int row, int col, boolean[] visited){
if(row>=0 && col>=0 && row < rows && col< cols && getsum(col)+getsum(row)<=threshold && !visited[row*cols+col]){
return true;
}
return false;
}
private static int getsum(int number){
int sum = 0;
while(number > 0){
sum = sum+number%10;
number = number/10;
}
return sum;
}
}
面试题14 剪绳子
public class cutstring{
public static void main(String[] args) {
int output1 = countsum(348);
int output2 = countsumFortanxin(348);
int output3 = matProductAfterCutting_2(348);
System.out.println(output1+","+output2+","+output3);
}
//动态规划
private static int countsum (int length){
if(length<2) return 0;
if(length == 2) return 1;
if(length == 3) return 2;
int[] arr = new int[length+1];
arr[1] = 1;
arr[2] = 2;
arr[3] = 3;
int max = 0;
for(int i=4;i<=length;i++){
max = 0;
for(int j = 1;j <= i/2;j++){
int product = arr[j]*arr[i-j];
if( product > max){
max = product;
}
}
arr[i] = max;
}
max = arr[length];
return max;
}
//贪心算法,尽量用3乘, 余2就乘4, 余1就乘2
private static int countsumFortanxin (int length){
if(length<2) return 0;
if(length == 2) return 1;
if(length == 3) return 2;
int countFor3 = length/3;// 7除以3余1
int modFor3 = length % 3;
int output = 0;
if(modFor3 == 0){
output = (int)Math.pow(3, countFor3);
}else if(modFor3 == 1){
output = (int)Math.pow(3, countFor3-1)*4;
}else if(modFor3 == 2){
output = (int)Math.pow(3, countFor3)*2;
}
return output;
}
private static int matProductAfterCutting_2(int length) {
if (length < 2) {
return 0;
}
if (length == 2) {
return 1;
}
if (length == 3) {
return 2;
}
// 当n>=5的时候,尽可能剪长度为3的绳子
int timeOf3 = length / 3;
// 当n=4的时候,剪成长度为2的两段
if (length - timeOf3 * 3 == 1) {
timeOf3 -= 1;
}
// 剪成长度为2的两段
int timeOf2 = (length - timeOf3 * 3) / 2;
return (int) ((Math.pow(3, timeOf3)) * (Math.pow(2, timeOf2)));
}
}
面试题 15 二进制数里有多少1
链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网
public class Solution {
//从n的2进制形式的最右边开始判断是不是1
/*
* 该解法如果输入时负数会陷入死循环,
* 因为负数右移时,在最高位补得是1
* 二本题最终目的是求1的个数,那么会有无数个
* 1了。
*/
//-------------可能陷入死循环的解法---------------------
public static int NumberOf1_CanNotUse(int n) {
int count = 0;
while (n != 0) {
/*
* 用1和n进行位与运算,
* 结果要是为1则n的2进制形式
* 最右边那位肯定是1,否则为0
*/
if ((n & 1) == 1) {
count++;
}
//把n的2进制形式往右推一位
n = n >> 1;
}
return count;
}
//---------------正解--------------------------------
//思想:用1(1自身左移运算,其实后来就不是1了)和n的每位进行位与,来判断1的个数
private static int NumberOf1_low(int n) {
int count = 0;
int flag = 1;
while (flag != 0) {
if ((n & flag) != 0) {
count++;
}
flag = flag << 1;
}
return count;
}
//--------------------最优解----------------------------
public static int NumberOf1(int n) {
int count = 0;
while (n != 0) {
++count;
n = (n - 1) & n;
}
return count;
}
public static void main(String[] args) {
//使用n=10,二进制形式为1010,则1的个数为2;
int n = -10;
System.out.println(n + "的二进制中1的个数:" + NumberOf1(n));
}
}
面试题16 数值的整数次方
public class Solution {
public double Power(double base, int exponent) {
if(exponent<0){
int absexponent = -exponent;
return 1.0/count(base,absexponent);
}else{
return count(base, exponent);
}
}
private static double count(double base, int exponent){
double result = 1.0;
for(int i=0;i<exponent;i++){
result = result*base;
}
return result;
}
}
\\用递归算法做
public class Solution {
public double Power(double base, int exponent) {
if(exponent == 0) return 1;
if(exponent == 1) return base;
int absexponent = Math.abs(exponent);
double result = Power(base, absexponent/2);
result = result * result;
if(absexponent % 2 == 1){
result = result * base;
}
if(exponent<0){
return 1.0/result;
}else{
return result;
}
}
}
面试题 17 从1 打印到n
https://blog.youkuaiyun.com/u013132035/article/details/80563507
常规解法:一步步注意手写演算,很巧妙
递归解法: 一步步注意手写演算,很巧妙。每次进位时都会回到第一个函数中的for循环,注意先用n=2 ,[][]来尝试。
面试题 18删除链表节点
//把第j个节点的值复制给第i个
private void delete(ListNode head, ListNode tobedeleted){
if(head == null || tobedeleted == null){
return;
}
if(tobedeleted.next != null){
tobedeleted.val = tobedeleted.next.val;
tobedeleted.next = tobedeleted.next.next;
}else if(head == tobedeleted){
head = null;
tobedeleted = null;
}else{
ListNode tmp = head;
while(tmp.next != null){
tmp = tmp.next;
}
tmp.next = null;
tobedeleted = null;
}
}
删除重复链表节点(没懂)
public static ListNode deleteDuplication(ListNode pHead) {
ListNode first = new ListNode(-1);//设置一个trick
first.next = pHead;
ListNode p = pHead;
ListNode last = first;
while (p != null && p.next != null) {
if (p.val == p.next.val) {
int val = p.val;
while (p!= null&&p.val == val)
p = p.next;
last.next = p;
} else {
last = p;
p = p.next;
}
}
return first.next;
}
//沁岩的做法,递归很容易懂。
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
// created by lqy niubility
public class Solution {
public ListNode deleteDuplication(ListNode pHead)
{
if(pHead==null)return null;
if(pHead.next==null)return pHead;
// 只有0个或1个结点,则返回
int val=pHead.val;
ListNode ln=pHead.next;
if(val!=ln.val){
pHead.next=deleteDuplication(ln);// 保留当前结点,从下一个结点开始递归
return pHead;
}else{
while(ln!=null && val==ln.val){
// 跳过值与当前结点相同的全部结点,找到第一个与当前结点不同的结点
ln=ln.next;
}
return deleteDuplication(ln); // 从第一个与当前结点不同的结点开始递归
}
}
}
面试题 20 表达数值的字符串
public class Solution {
public boolean isNumeric(char[] str) {
boolean sign = false;
boolean decimal = false;
boolean hasE = false;
for(int i = 0;i< str.length;i++){
if(str[i] == 'e' || str[i] == 'E'){
if (i == str.length-1) return false;//e后面一定要跟着数字
if (hasE) return false; //不能有两个e
hasE = true;
}else if(str[i] == '+' || str[i] == '-'){
if( sign && str[i-1] !='e' && str[i-1] != 'E') return false;
// 第二次出现+必须紧跟在e后面
if(!sign && i>0 && str[i-1]!='e' && str[i-1]!='E') return false;
// 第一次出现+的话,非开头,也必须跟在e后面
sign = true;
}
else if(str[i]=='.'){
if (hasE || decimal) return false;
//e后面不能接小数,小数点不能出现两次
decimal = true;
}else if(str[i] < '0' || str[i] > '9'){ //不合法字符
return false;
}
}
return true;
}
}
正则解法,看我另外一篇原创 https://blog.youkuaiyun.com/weixin_39285712/article/details/89926985
调正数组顺序奇数在偶数前面
//建立两个数组,空间换时间
function reOrderArray(array)
{
// write code here
let even = [];
let old = [];
for(let i = 0;i<array.length;i++){
if(isEven(array[i])){
even.push(array[i]);
}else{
old.push(array[i]);
}
}
for(let j = 0;j<even.length;j++){
old.push(even[j]);
}
return old;
}
function isEven(num){
if(num % 2 ==0)
return true;
}
//剑指offer做法,前后两个指针。
public class Solution {
public void reOrderArray(int [] array) {
int i = 0;
int j = array.length-1;
while(i < j){
while(i< j && array[i] % 2 == 1){
i++;
}
while (i<j && array[j] % 2 == 0){
j--;
}
if(i < j){
int tmp = array[j];
array[j] = array[i];
array[i] = tmp;
}
}
}
}
//冒泡做法
public class Solution {
public void reOrderArray(int [] array) {
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-1-i;j++){
if((array[j]%2)== 0 && (array[j+1]%2)==1){
int tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
}
}
}
}
}
鲁棒性:啥叫鲁棒型就是不管程序在什么情况,什么输入,什么网络下都不会崩溃。特别是奇奇怪怪的输入。
链表中倒数第k个节点
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head == null) return null;
if(k == 0) return null;
ListNode first = head;
ListNode second = null;
for(int i = 0;i<k-1;i++){
if(first.next != null){
first = first.next;
}else{
return null;
}
}
second = head;
while(first.next != null){
first = first.next;
second = second.next;
}
return second;
}
}
反思,当我们用一个指针不能解决的问题可以考虑用两个指针遍历链表。可以让一个指针走的快一点。
比如求中间节点的链表题,可以让一个指针走两步,另一个走一步。
面试题 23 :链表中环的入口节点
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ListNode EntryNodeOfLoop(ListNode pHead)
{
ListNode meetingnode = meetnode(pHead);
int count = 1;
if(meetingnode == null) return null;
ListNode p1= meetingnode;
while(p1.next != meetingnode){
p1 = p1.next;
count++;
}
ListNode first = pHead;
ListNode second = pHead;
for(int j=0;j<count;j++){
first = first.next;
}
while(first != second){
first = first.next;
second = second.next;
}
return second;
}
private static ListNode meetnode(ListNode head){
if(head == null) return null;
if(head.next == null) return null;
ListNode slow = head.next;
ListNode fast = slow.next;
while(fast != null && slow != null){
if(fast == slow) return fast;
fast = fast.next;
slow = slow.next;
if(fast != slow){
fast = fast.next;
}
}
return null;
}
}
面试题 24反转链表
//我们需要设置三个指针来保存前中后三个节点。
/*
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 null;
if(head.next == null) return head;
ListNode pnext = head;
ListNode pbefore = null;
ListNode pafter = null;
ListNode preversehead = null;
while(pnext != null){
pafter = pnext.next;
if(pafter == null) preversehead = pnext;
pnext.next = pbefore;
pbefore = pnext;
pnext = pafter;
}
return preversehead;
}
}
面试题 25 合并两个有序链表
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
ListNode tmp = new ListNode(20);
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null) return list2;
if(list2 == null) return list1;
ListNode mergednode = null;
ListNode current = null;
while(list1!=null && list2 !=null){
if(list1.val > list2.val){
if(mergednode == null) {
mergednode = current = list2;
}else{
current.next = list2;
current = current.next;
}
list2 = list2.next;
}else{
if(mergednode == null) {
mergednode = current= list1;
}else{
current.next = list1;
current = current.next;
}
list1 = list1.next;
}
}
if(list1 == null){
current.next = list2;
}else{
current.next = list1;
}
return mergednode;
}
}
//递归算法
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
ListNode tmp = new ListNode(20);
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null) return list2;
if(list2 == null) return list1;
if(list1.val > list2.val){
list2.next = Merge(list1, list2.next);
return list2;
}else{
list1.next = Merge(list1.next, list2);
return list1;
}
}
}
面试题26 树的子结构
//用递归来做
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
boolean result = false;
if(root1 == null || root2 == null) return false;
if(root1.val == root2.val){
result = DoesTree2likeTree2 (root1,root2);
}
if(!result){
result = HasSubtree(root1.left, root2);
}
if(!result){
result = HasSubtree(root1.right, root2);
}
return result;
}
private boolean DoesTree2likeTree2 (TreeNode root1, TreeNode root2){
if(root2 == null) return true;
if(root1 == null) return false;
if(root1.val != root2.val){
return false;
}
return DoesTree2likeTree2(root1.left, root2.left) && DoesTree2likeTree2(root1.right, root2.right);
}
}
面试题 二叉树的镜像
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public void Mirror(TreeNode root) {
if(root == null) return;
if(root.left == null && root.right == null) return;
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
if(root.right != null){
Mirror(root.right);
}
if(root.left != null){
Mirror(root.left);
}
}
}
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function Mirror(root)
{
// write code here
if(root == null) return;
if(root.left == null && root.right == null) return;
let tmp = root.left;
root.left = root.right;
root.right = tmp;
if(root.right != null){
Mirror(root.right);
}
if(root.left != null){
Mirror(root.left);
}
}
面试题28 对称的二叉树
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
boolean isSymmetrical(TreeNode pRoot)
{
return isSymmetrical(pRoot, pRoot);
}
private boolean isSymmetrical(TreeNode pRoot1, TreeNode pRoot2){
if(pRoot1 == null && pRoot2 == null) return true;
if(pRoot1 == null || pRoot2 == null) return false;
if(pRoot1.val != pRoot2.val ) return false;
return isSymmetrical(pRoot1.left, pRoot2.right) && isSymmetrical(pRoot1.right, pRoot2.left);
}
}
面试题29 顺时针打印矩阵
这道题就是找规律,首先确定layer层数,就是找规律看绕几圈。注意三个break就是在特殊情况下不能继续画圈圈。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer>();
if(matrix.length == 0) return result;//如果矩阵行数为0,说明是空矩阵,则直接返回空列表
int columns = matrix[0].length;
int rows = matrix.length;
if(columns == 0) return result; //如果矩阵行数不为0,矩阵的列数为0,意味着矩阵由空元素组成,依然返回空列表
int layers = (Math.min(columns, rows)-1)/2+1;
for(int i=0;i<layers;i++){
for(int k = i; k< columns-i;k++){
result.add(matrix[i][k]);
}
if(i+1>rows-1-i) break;
for(int k = i+1; k< rows-i;k++){
result.add(matrix[k][columns-1-i]);
}
if(columns-2-i<0) break;
for(int k = columns-2-i; k>=i;k--){
result.add(matrix[rows-1-i][k]);
}
if(rows-2-i<0) break;
for(int k = rows-2-i; k>i;k--){
result.add(matrix[k][i]);
}
}
return result;
}
}
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> result = new ArrayList<Integer>();
if(matrix.length == 0) return result;
int columns = matrix[0].length;
int rows = matrix.length;
if(columns == 0) return result;
int left = 0;
int right = columns-1;
int top = 0;
int bottom = rows-1;
while (left <= right && top <= bottom)
{
// left to right
for (int i = left; i <= right; ++i) result.add(matrix[top][i]);
// top to bottom
for (int i = top + 1; i <= bottom; ++i) result.add(matrix[i][right]);
// right to left
for (int i = right - 1; i >= left&&top<bottom; --i) result.add(matrix[bottom][i]);
// bottom to top
for (int i = bottom - 1; i > top&&right>left; --i) result.add(matrix[i][left]);
left++;
top++;
right--;
bottom--;
}
return result;
}
}
面试题30 包含min函数 的栈
import java.util.Stack;
public class Solution {
Stack<Integer> mainstack = new Stack<Integer>();
Stack<Integer> tmpstack = new Stack<Integer>();
public void push(int node) {
mainstack.push(node);
if(tmpstack.isEmpty()){
tmpstack.push(node);
}else if(node < tmpstack.peek()){ //只有当数字小于辅助栈顶端数字时才push
tmpstack.push(node);
}
}
public void pop() {
if(tmpstack.peek()==mainstack.peek()) //只有当两个栈顶端数字相同时才pop
tmpstack.pop();
mainstack.pop();
}
public int top() {
return mainstack.peek();
}
public int min() {
return tmpstack.peek();
}
}
面试题31 栈的压入弹出序列
摘选自 https://www.nowcoder.com/profile/844008/codeBookDetail?submissionId=1522453
思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
举例:
入栈1,2,3,4,5
出栈4,5,3,2,1
首先1入辅助栈,此时栈顶1≠4,继续入栈2
此时栈顶2≠4,继续入栈3
此时栈顶3≠4,继续入栈4
此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
此时栈顶3≠5,继续入栈5
此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
….
依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length == 0 || popA.length == 0)
return false;
Stack<Integer> s = new Stack<Integer>();
//用于标识弹出序列的位置
int popIndex = 0;
for(int i = 0; i< pushA.length;i++){
s.push(pushA[i]);
//如果栈不为空,且栈顶元素等于弹出序列
while(!s.empty() &&s.peek() == popA[popIndex]){
//出栈
s.pop();
//弹出序列向后一位
popIndex++;
}
}
return s.empty();
}
}
面试题32 打印二叉树
//使用二叉树
import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
ArrayList<Integer> result = new ArrayList<>();
if(root == null) return result;
queue.offer(root);
while(!queue.isEmpty()){
TreeNode tmp = queue.poll();
result.add(tmp.val);
if(tmp.left!=null) queue.offer(tmp.left);
if(tmp.right!=null) queue.offer(tmp.right);
}
return result;
}
}
分行打印二叉树
https://blog.youkuaiyun.com/qq1263292336/article/details/76168094
之字型打印二叉树
链接:https://www.nowcoder.com/questionTerminal/91b69814117f4e8097390d107d2efbe0
来源:牛客网
设立两个栈,打印一个栈里节点时,它的子节点放在另一个栈里,当一层所有节点打印完毕时,交换这两个栈并继续下一个层。
public static ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
int layer = 1;
//s1存奇数层节点
Stack<TreeNode> s1 = new Stack<TreeNode>();
s1.push(pRoot);
//s2存偶数层节点
Stack<TreeNode> s2 = new Stack<TreeNode>();
ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();
while (!s1.empty() || !s2.empty()) {
if (layer%2 != 0) {
ArrayList<Integer> temp = new ArrayList<Integer>();
while (!s1.empty()) {
TreeNode node = s1.pop();
if(node != null) {
temp.add(node.val);
System.out.print(node.val + " ");
s2.push(node.left);
s2.push(node.right);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
System.out.println();
}
} else {
ArrayList<Integer> temp = new ArrayList<Integer>();
while (!s2.empty()) {
TreeNode node = s2.pop();
if(node != null) {
temp.add(node.val);
System.out.print(node.val + " ");
s1.push(node.right);
s1.push(node.left);
}
}
if (!temp.isEmpty()) {
list.add(temp);
layer++;
System.out.println();
}
}
}
return list;
}
33 二叉树后序遍历
用递归,最后一位是根节点,前半部是左子树,右半边是右子树,右子树不能出现小于根节点的树。
public class Solution {
public boolean VerifySquenceOfBST(int [] sequence) {
if(sequence.length == 0) return false;
return isBST(sequence, 0 , sequence.length-1);
}
private static boolean isBST(int [] sequence, int start, int end){
if(end<=start) return true;
int root = sequence[end];
int i = start;
for(;i<end;i++){
if(sequence[i]>root){
break;
}
}
for(int j=i;j<end;j++){
if(sequence[j]<root){
return false;
}
}
return isBST(sequence,start,i-1) && isBST(sequence,i, end-1);
}
}
34 二叉树中和为某一值的路径
import java.util.ArrayList;
/**
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
ArrayList<ArrayList<Integer>> allpath = new ArrayList<>();
ArrayList<Integer> path = new ArrayList<>();
public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
if(root == null) return allpath;
path.add(root.val);
target = target - root.val;//现在target变成这个了
if(root.left == null && root.right == null && target == 0){
allpath.add(new ArrayList<Integer>(path));//假如没有叶子节点并且target为0,添加进allpath
//为啥要新建构造函数,否则后面list.add和list.remove都是改变应用,会影响原来的list.
}
FindPath(root.left, target);
FindPath(root.right, target);
path.remove(path.size()-1);//无论是不是匹配都要删除最后一个回退
return allpath;
}
}
35 复杂链表的复制
36 二叉搜索树与双向链表
https://www.nowcoder.com/profile/163334/codeBookDetail?submissionId=1515508
方法一:非递归版
解题思路:
1.核心是中序遍历的非递归算法。
2.修改当前遍历节点与前一遍历节点的指针指向。
import java.util.Stack;
public TreeNode ConvertBSTToBiList(TreeNode root) {
if(root==null)
return null;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
TreeNode pre = null;// 用于保存中序遍历序列的上一节点
boolean isFirst = true;
while(p!=null||!stack.isEmpty()){
while(p!=null){
stack.push(p);
p = p.left;
}
p = stack.pop();
if(isFirst){
root = p;// 将中序遍历序列中的第一个节点记为root
pre = root;
isFirst = false;
}else{
pre.right = p;
p.left = pre;
pre = p;
}
p = p.right;
}
return root;
}
方法二:递归版
解题思路:
1.将左子树构造成双链表,并返回链表头节点。
2.定位至左子树双链表最后一个节点。
3.如果左子树链表不为空的话,将当前root追加到左子树链表。
4.将右子树构造成双链表,并返回链表头节点。
5.如果右子树链表不为空的话,将该链表追加到root节点之后。
6.根据左子树链表是否为空确定返回的节点。
public TreeNode Convert(TreeNode root) {
if(root==null)
return null;
if(root.left==null&&root.right==null)
return root;
// 1.将左子树构造成双链表,并返回链表头节点
TreeNode left = Convert(root.left);
TreeNode p = left;
// 2.定位至左子树双链表最后一个节点
while(p!=null&&p.right!=null){
p = p.right;
}
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if(left!=null){
p.right = root;
root.left = p;
}
// 4.将右子树构造成双链表,并返回链表头节点
TreeNode right = Convert(root.right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if(right!=null){
right.left = root;
root.right = right;
}
return left!=null?left:root;
}
方法三:改进递归版
解题思路:
思路与方法二中的递归版一致,仅对第2点中的定位作了修改,新增一个全局变量记录左子树的最后一个节点。
// 记录子树链表的最后一个节点,终结点只可能为只含左子树的非叶节点与叶节点
protected TreeNode leftLast = null;
public TreeNode Convert(TreeNode root) {
if(root==null)
return null;
if(root.left==null&&root.right==null){
leftLast = root;// 最后的一个节点可能为最右侧的叶节点
return root;
}
// 1.将左子树构造成双链表,并返回链表头节点
TreeNode left = Convert(root.left);
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if(left!=null){
leftLast.right = root;
root.left = leftLast;
}
leftLast = root;// 当根节点只含左子树时,则该根节点为最后一个节点
// 4.将右子树构造成双链表,并返回链表头节点
TreeNode right = Convert(root.right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if(right!=null){
right.left = root;
root.right = right;
}
return left!=null?left:root;
}
37 字符串的序列化
前序排列,递归,碰到节点为null的时候输出“#“,反向序列的时候也是”1,2,4,#,#,#,#,5,#,8,#“
/*
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
*/
public class Solution {
String Serialize(TreeNode root) {
if(root == null) return "";
StringBuilder sb = new StringBuilder();
Serialize2(root, sb);
return sb.toString();
}
void Serialize2 (TreeNode root,StringBuilder sb){
if(root == null){
sb.append("#,");
return;
}
sb.append(root.val);
sb.append(",");
Serialize2(root.left,sb);
Serialize2(root.right,sb);
}
int index = -1;
TreeNode Deserialize(String str) {
if (str.length() == 0) return null;
String[] str1 = str.split(",");
return Deserialize2(str1);
}
TreeNode Deserialize2(String[] str){
index++;
if(!str[index].equals("#")){
TreeNode root = new TreeNode(0);
root.val = Integer.parseInt(str[index]);
root.left = Deserialize2(str);
root.right = Deserialize2(str);
return root;
}
return null;
}
}
38 字符串的排列
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res = new ArrayList<>();
//nowcoder上用list,这里用arraylist就可以了
if(str.length() == 0)
return res;
char[] arrstr = str.toCharArray();
Permutation1(arrstr, 0 , res);
Collections.sort(res);//排序不然会出错
return res;
}
public void Permutation1(char[] str , int i , ArrayList<String> res){
if(i == str.length-1){
if(!res.contains(new String(str))){ //把字符数组变成字符串
res.add(new String(str));
return;
}
}else{
for(int j=i;j < str.length;j++){
//最外层循环是交换第一个与后面每个元素
swap(str,i,j);
Permutation1(str, i+1, res);
swap(str,i,j); //第二次交换是为了把之前交换回去的换回来
}
}
}
public void swap(char[] str, int a, int b){
char tmp = str[a];
str[a] = str[b];
str[b] = tmp;
}
}
39 数组中超过一半的数字
//首先进行排序,然后超过一般数字肯定就是中位数,然后验证它的数量是不是超过了一半多
import java.util.Arrays;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
Arrays.sort(array);
int result = array[array.length/2];
int times = 0;
for(int i = 0; i< array.length;i++){
if(array[i] == result) times++;
}
if(times*2 <= array.length){
return 0;
}else{
return result;
}
}
}
//javascript 除以2需要用 math.floor手动向下取整
function MoreThanHalfNum_Solution(numbers)
{
// write code here
numbers.sort();
let result = numbers[Math.floor(numbers.length/2)];
let times = 0;
for(let i = 0; i< numbers.length;i++){
if(numbers[i] == result) times++;
}
if(times*2 <= numbers.length){
return 0;
}else{
return result;
}
}
//一种很巧妙的方法,我们要找的数字他的数量比其他数字加起来还多,所以最后一次把次数设置为1的数字就是我们要找的数字。
import java.util.Arrays;
public class Solution {
public int MoreThanHalfNum_Solution(int [] array) {
if(array.length == 0 ) return 0;
int time2 = 1;
int result2 = array[0];
for(int j=1; j< array.length;j++){
if(time2 ==0){
time2 = 1;
result2 = array[j];
}else if(array[j] == result2){
time2++;
}else {
time2--;
}
}
int times = 0;
for(int i = 0; i< array.length;i++){
if(array[i] == result2) times++;
}
if(times*2 <= array.length){
return 0;
}else{
return result2;
}
}
}
40 最小的K个数字
//最简单的做法,排序
import java.util.Arrays;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(k>input.length) return res;
Arrays.sort(input);
for(int i=0;i<k;i++){
res.add(input[i]);
}
return res;
}
}
//冒泡做法,只需要外面循环k次
import java.util.Arrays;
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(k>input.length) return res;
for(int i = 0; i<k;i++){
for(int j = 0;j<input.length-1-i;j++){
if(input[j]<input[j+1]){
int tmp = input[j];
input[j] = input[j+1];
input[j+1] = tmp;
}
}
res.add(input[input.length-i-1]);
}
return res;
}
}