03[1]. 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
代码实现:
//方法一: 时间复杂度直接爆表,空间复杂度也会,
// 因为随着 数组的扩大, 空间复杂度会变大;然后就是时间复杂度,因为是 HashMap,可能后面会转为红黑树,那也要 O(nlog(n))
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums.length<=0){
return -1;
}
HashMap<Integer,Integer> hashMap = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if(hashMap.containsValue(nums[i])){
return nums[i];
}
hashMap.put(i,nums[i]);
}
return -1;
}
}
//方法二:
//首先是空间复杂度是 O(1) , 先排序了;
//其次是时间复杂度, 这里由于已经是排好序的了,所以时间复杂度是O(n)
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums.length<=0){
return -1;
}
Arrays.sort(nums);
HashMap<Integer,Integer> hashMap = new HashMap<>();
for (int i = 0; i <= nums.length-2; i++) {
int j = i+1;
if(nums[i]==nums[j]){
return nums[i];
}
}
return -1;
}
}
//方法三:
//1.这里采用的是 哈希法,利用空间换时间,空间复杂度O(n),时间复杂度O(n)
// 就是让 nums数组的值, 对应哈希数组的下标, 如果出现了某一个下标,就让该下标对应的值 +1,值大于1的说明是重复的。
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums.length<=0){
return -1;
}
int[] arr = new int[nums.length];
for(int i=0; i<nums.length;i++){
//就是让 nums数组的值, 对应哈希数组的下标,
//如果出现了某一个下标,就让该下标对应的值 +1,值大于1的说明是重复的。
arr[nums[i]]++;
if(arr[nums[i]]>1){
return nums[i];
}
}
return -1;
}
}
//★牛批★ 鸽巢原理 方法四:
// 因为出现的元素值 < nums.length;
// 所以我们可以将见到的元素 放到索引的位置,如果交换时,发现索引处已存在该元素则重复
// O(N) 空间O(1)
class Solution {
public int findRepeatNumber(int[] nums) {
if(nums.length<=0){
return -1;
}
for(int i=0; i<nums.length;i++){
//这里就是让 i 和 nums[i]比较,如果值不相等;
while(nums[i]!=i){
//然后再 比较 以nums[i]为下标, 比较 nums[nums[i]] 和 nums[i] 是否相等,
//如果相等,说明:这里,在nums[i]为下标的位置处,已经有nums[nums[i]]==nums[i]
//这里在比较相等,说明当前值nums[i] 和 nums[nums[i]] 重复,返回即可。
if(nums[nums[i]] == nums[i])
return nums[i];
// 如果不相等,那就让 下标nums[i] 和 下标i 上的值交换
// 此时,是使得 下标为i上的值 和 以nums[i]为下标 在值上相等。
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
return -1;
}
}
实例:
数值:[2,3,4,1,2]
下标:[0,1,2,3,4]
i=0为例:
从while开始
0!=(nums[0]=2)
(4=nums[2]) == 2
不等,这里开始交换
int temp = 2;
num[0] = (num[temp]=num[2]=4)
(num[temp]=num[2])= 2
03[2].不修改数组找出重复的数字
在一个长度为n+1的数组里的呃所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如:如果输入长度为8的数组{2,3,5,4,3,2,6,7}那么对应的输入都是重复的数字2或者3。
代码实现:
public class DuplicationSearch {
public static void main(String[] args) {
int[] nums = {2,3,5,4,3,2,6,7};
int[] nums1 = {6,6,6,6,6,6,6,6};
System.out.println(getDuplication(nums1,nums1.length));
}
public static int getDuplication(int[] nums,int length){
if(nums==null || length<=0){
return -1;
}
//这个 start、end是该数组的取值范围
int start = 1;
int end = length-1;
while(end>=start){
//这个 +start用的是真的巧妙
int middle = ((end-start)>>1) + start;
//看清,这里是middle
int count = countRange(nums,length,start,middle);
//二分法最终会走到 start == end
if(start==end){
if(count>1){
return start;
}else {
break;
}
}
/**
* 如果count的值比
*/
if(count>((middle-start)+1)){
end = middle;
}else {
start = middle+1;
}
}
return -1;
}
public static int countRange(int[] numbers,int length,int start,int end){
if(numbers==null){
return -1;
}
int count = 0;
for (int i = 0; i < length; i++) {
/**
* 这个比较的就是 numbers数组中的值 在 start~end范围内的数有多少个
*/
if(numbers[i]>=start && numbers[i]<=end){
count++;
}
}
return count;
}
}
04. 二维数组中的查找
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5
,返回 true
。
给定 target = 20
,返回 false
。
限制:
0 <= n <= 1000
0 <= m <= 1000
代码实现:
/**
解题思路:
● 若数组为空,返回 false
● 初始化行下标为 0,列下标为二维数组的列数减 1
● 重复下列步骤,直到行下标或列下标超出边界
○ 获得当前下标位置的元素 num
○ 如果 num 和 target 相等,返回 true
○ 如果 num 大于 target,列下标减 1
○ 如果 num 小于 target,行下标加 1
● 循环体执行完毕仍未找到元素等于 target ,说明不存在这样的元素,返回 false`
*/
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length==0){
return false;
}
int i = 0;
int j = matrix[0].length-1;
while(i<matrix.length && j>=0){
if(target == matrix[i][j]){
return true;
}else if(target < matrix[i][j]){
j--;
}else{
i++;
}
}
return false;
}
}
05. 替换空格
请实现一个函数,把字符串 s
中的每个空格替换成"%20"。
示例 1:
输入:s = "We are happy."
输出:"We%20are%20happy."
限制:
0 <= s 的长度 <= 10000
代码实现:
//方法一:
class Solution {
public String replaceSpace(String s) {
if(s.length() == 0){
return "";
}
return s.replaceAll(" ","%20");
}
}
//方法二:
// 占内存的情况,这两种方法基本一样;
// 在时间消耗上:方法一:2ms, 而方法二:直接0ms
class Solution {
public String replaceSpace(String s) {
if(s.length() == 0){
return "";
}
char[] charArr = s.toCharArray();
StringBuffer bf = new StringBuffer();
for(int i=0;i<s.length();i++){
if(charArr[i]==' '){
bf.append("%20");
}else{
bf.append(charArr[i]);
}
}
return bf.toString();
}
}
06. 从尾到头打印链表
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
示例 1:
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
代码实现:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
//感觉不论怎么搞,空间复杂度是降不下来的。
//方法一:
class Solution {
public int[] reversePrint(ListNode head) {
if(head==null){
return new int[0];
}
ArrayList<Integer> list = new ArrayList<>();
while (head!=null){
list.add(head.val);
head = head.next;
}
int[] arr = new int[list.size()];
int length = list.size()-1;
for(int i=0; i <= list.size()-1;i++){
arr[i] = list.get(length--);
}
return arr;
}
}
//方法二:利用栈,操作,但是实际运行效果还没有上面的效果要好,这个 3ms,上面1ms,内存占用基本大小一样
class Solution {
public int[] reversePrint(ListNode head) {
if(head==null){
return new int[0];
}
Stack<Integer> stack = new Stack<Integer>();
while (head!=null){
stack.push(head.val);
head = head.next;
}
int[] arr = new int[stack.size()];
int length = stack.size();
for (int i = 0; i < length ; i++) {
arr[i] = stack.pop();
}
return arr;
}
}
07. 重建二叉树
已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树;
已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树;
但是已知前序遍历序列和后序遍历序列,是不能确定一棵二叉树的;
即:没有中序遍历序列的情况下是无法确定一颗二叉树的。
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:
0 <= 节点个数 <= 5000
代码实现:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
int preStart = 0;
int preEnd = preorder.length-1;
int inStart = 0;
int inEnd = inorder.length-1;
return reBuildTree(preorder,preStart,preEnd,inorder,inStart,inEnd);
}
public TreeNode reBuildTree(int[] preorder,int preStart,int preEnd,
int[] inorder,int inStart,int inEnd){
if(preStart>preEnd || inStart>inEnd){
return null;
}
//这里是是preStart,每一次递归过来 new的是当前节点
TreeNode root = new TreeNode(preorder[preStart]);
for(int i = inStart ; i<=inEnd ; i++){
if(preorder[preStart] == inorder[i]){
//这里preStart+(i-inStart) :preStart加的是 inStart到 i的距离
root.left = reBuildTree(preorder,preStart+1,preStart+i-inStart,
inorder,inStart,i-1);
//preStart+i-inStart+1 ,刚好就是preStart+(i-inStart)+1
root.right = reBuildTree(preorder,preStart+i-inStart+1,preEnd,
inorder,i+1,inEnd);
break;
}
}
return root;
}
}
输入:
[3,9,20,15,7]
[9,3,15,20,7]
输出
[3,9,20,null,null,15,7]
预期结果
[3,9,20,null,null,15,7]
-
中序遍历和后序遍历:
public static TreeNode buildTree(int[] preorder, int[] inorder) { int preStart = 0; int preEnd = preorder.length-1; int inStart = 0; int inEnd = inorder.length-1; return reInAndAfterBuildTree(preorder,preStart,preEnd,inorder,inStart,inEnd); } /** * 中序和后续 * @return */ public static TreeNode reInAndAfterBuildTree(int[] afterOrder, int afterStart,int afterEnd, int[] inorder, int inStart,int inEnd){ // 防止前后交叉导致已选过的数值重复选中 if(afterStart>afterEnd || inStart>inEnd){ return null; } // 防止数组越界 if (afterStart < 0 || afterEnd < 0 || inStart < 0 || inEnd < 0) { return null; } TreeNode root = new TreeNode(afterOrder[afterEnd]); int index = indexOfRootInMid(afterOrder[afterEnd],inorder); // 所选节点左子树的数量 int lefNum = index - inStart; root.left = reInAndAfterBuildTree(afterOrder,afterStart,afterStart+lefNum-1, inorder,inStart,index-1); root.right = reInAndAfterBuildTree(afterOrder,afterStart+lefNum,afterEnd-1, inorder,index+1,inEnd); return root; } // 获得所选子树的根节点在中序数组中的下标 public static int indexOfRootInMid(int afterRoot , int[] inOrder){ for (int i = 0; i < inOrder.length; i++) { if(afterRoot == inOrder[i]){ return i; } } return -1; } //后续遍历 public static void afterOrder(TreeNode root){ if(root==null){ return; } afterOrder(root.left); afterOrder(root.right); System.out.print(root.val+"\t"); } public static void main(String[] args) { int[] a = {4,6,7,5,2,9,8,3,1}; int[] b = {4,2,6,5,7,1,3,9,8}; TreeNode node = buildTree(a, b); afterOrder(node); } //运行结果: 4 6 7 5 2 9 8 3 1
08. 二叉树的下一个节点
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
分析:
就是有一颗二叉树,然后给了一个结点,按中序遍历,输入这个结点的下一个结点。
实例:
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
分为两种旅客
代码实现:
/*
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)
{
if(pNode == null){
return null;
}
if(pNode.right!=null){ //如果有右子树,则找右子树的最左节点
pNode = pNode.right;
while(pNode.left!=null){
pNode = pNode.left;
}
return pNode;
}
while(pNode.next!=null){ //没右子树,则找第一个当前节点是父节点左孩子的节点
if(pNode.next.left==pNode){
return pNode.next;
}
pNode = pNode.next;
}
return null; //退到了根节点仍没找到,则返回null
}
public static void main(String[] args) {
TreeLinkNode root = new TreeLinkNode(1);
root.left = new TreeLinkNode(2);
root.right = new TreeLinkNode(3);
root.left.next = root;
root.right.next = root;
root.left.left = new TreeLinkNode(4);
root.left.right = new TreeLinkNode(5);
root.left.left.next = root.left;
root.left.right.next = root.left;
root.right.left = new TreeLinkNode(6);
root.right.right = new TreeLinkNode(7);
root.right.left.next = root.right;
root.right.right.next = root.right;
root.left.right.left = new TreeLinkNode(8);
root.left.right.right = new TreeLinkNode(9);
root.left.right.left.next = root.left.right;
root.left.right.right.next = root.left.right;
System.out.println(GetNext(root.left.right.right));
}
}
09[1]. 用两个栈实现队列
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
示例 1:
输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:
输入:
["CQueue","deleteHead","appendTail","appendTail","deleteHead","deleteHead"]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]
提示:
1 <= values <= 10000
最多会对 appendTail、deleteHead 进行 10000 次调用
代码实现:
//这个题目也给了一个思路:
//1° LinkedList 的 push 和 pop 组合是一个栈;
//2° LinkedList 的 add 和 pop 组合是一个队列;
class CQueue {
LinkedList<Integer> stack1;
LinkedList<Integer> stack2;
public CQueue() {
stack1 = new LinkedList<>();
stack2 = new LinkedList<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if(stack2.isEmpty()){
if(stack1.isEmpty()){
return -1;
}
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}else{
return stack2.pop();
}
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
09[2]. 用两个队列实现栈
代码实现:
/**
* 两个队列做一个栈:
* 添加:哪个队列有元素,往哪个队列中添加;
* 删除:哪个队列有元素,就将该队列中的元素全部移动到另外一个队列,只保留了一个元素,该元素就是要删除的元素。
*/
public class DoubleQueueDoStack {
static Queue<Integer> queue1;
static Queue<Integer> queue2;
public DoubleQueueDoStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/**
* 添加的时候:
* 如果两个队列都为空,往哪个里面插入都可以;
* 如果队列不为空,那两个队列也只能是一个队列为空、一个队列不为空
* @param value
* @return
*/
public boolean appendTail(int value) {
if (!queue1.isEmpty()) {
return queue1.offer(value);
} else {
return queue2.offer(value);
}
}
/**
* 删除:一定是删除 移动队列元素后,剩下一个元素的队列删除
* @return
*/
public int deleteHead() {
if(!queue1.isEmpty() && queue2.isEmpty()){
while (queue1.size()!=1){
queue2.offer(queue1.poll());
}
return queue1.poll();
}
if(queue1.isEmpty() && !queue2.isEmpty()){
while (queue2.size()!=1){
queue1.add(queue2.poll());
}
return queue2.poll();
}
return -1;
}
public static void main(String[] args) {
DoubleQueueDoStack doStack = new DoubleQueueDoStack();
doStack.appendTail(1);
doStack.appendTail(2);
doStack.appendTail(3);
doStack.appendTail(4);
System.out.println("----------------");
System.out.println("queue2:"+queue2.toString());
System.out.println("---------删除-------");
doStack.deleteHead();
System.out.println("queue1:"+queue1.toString());
System.out.println("queue2:"+queue2.toString());
System.out.println("---------添加-------");
doStack.appendTail(5);
System.out.println("queue1:"+queue1.toString());
System.out.println("queue2:"+queue2.toString());
System.out.println("---------删除-------");
doStack.deleteHead();
System.out.println("queue1:"+queue1.toString());
System.out.println("queue2:"+queue2.toString());
}
}
//运行结果:
----------------
queue2:[1, 2, 3, 4]
---------删除-------
queue1:[1, 2, 3]
queue2:[]
---------添加-------
queue1:[1, 2, 3, 5]
queue2:[]
---------删除-------
queue1:[]
queue2:[1, 2, 3]
10- I. 斐波那契数列
写一个函数,输入 n
,求斐波那契(Fibonacci)数列的第 n
项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
代码实现:
//牛批
class Solution {
public int fib(int n) {
int a = 0, b = 1, sum;
for(int i = 0; i < n; i++){
sum = (a + b) % 1000000007;
a = b;
b = sum;
}
return a;
}
}
//这种方式应该也行,就是超出时间限制了 。
class Solution {
public int fib(int n) {
if(n==0){
return 0;
}
if(n==1){
return 1;
}
return (fib(n-1)+fib(n-2))%1000000007;
}
}
10- II. 青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
示例 3:
输入:n = 0
输出:1
提示:
0 <= n <= 100
运行结果:
class Solution {
public int numWays(int n) {
int a=1,b=1,sum;
for(int i=0;i<n;i++){
sum = (a+b)%1000000007;
a = b;
b = sum;
}
return a;
}
}
10-Ⅲ. 变态青蛙跳
一只青蛙一次可以跳上1级台阶,也可以跳上2级… 它也可以跳上n级台阶,此时该青蛙跳上一个n级的台阶总共有多少中跳法。
分析:
1° 每一个台阶都有跳与不跳两种(除了最后一个台阶),最后一个台阶必须跳。
∴ f(n) = 2的n-1次方
2° ∵ n个台阶,第一步有n中跳法:跳1阶,跳两阶… 跳n阶;
跳1阶,剩下n-1阶,则剩下跳法f(n-1);
跳2阶,剩下n-2阶,则剩下跳法f(n-2);
∴ f(n) = f(n-1) + f(n-2) + … + f(1);
f(n-1) = f(n-2) + … + f(1);
∴ f(n) = 2*f(n-1);
= 2的n-1次方 * f(1);
=2的n-1次方
代码实现:
public class Solution {
public int JumpFloorII(int target) {
if(target<=0){
return -1;
}
return new Double(Math.pow(2,target-1)).intValue();
}
}
//这里求n次方,可以用 16题的 数值的整次方的方式求解
11[1]. 旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。
示例 1:
输入:[3,4,5,1,2]
输出:1
示例 2:
输入:[2,2,2,0,1]
输出:0
代码实现:
//方法一:最笨方法,部分有序,
//顺序找到一个小于当前元素的下一个元素即可。
//如果不是,那就返回第一个元素
class Solution {
public int minArray(int[] numbers) {
if(numbers.length==0){
return -1;
}
if(numbers.length==1){
return numbers[0];
}
int i,j=1;
for(i=0;i<numbers.length;i++){
//这里需要注意,j的值是比i的大1
if(j<numbers.length && numbers[i]>numbers[j]){
return numbers[j];
}
j++;
}
//如果不是,那就返回第一个元素
return numbers[0];
}
}
//方法二:夹逼法
class Solution {
public int minArray(int[] numbers) {
if(numbers.length==0){
return -1;
}
if(numbers.length==1){
return numbers[0];
}
//这里对特殊情况进行输出,如果没有 “旋转”,那么只用比较 第一个和最后一个元素的大小即可(数组本身就是升序的。)。
if(numbers[0]<numbers[numbers.length-1]){
return numbers[0];
}
//★这里夹逼比较★
int i=0,j=numbers.length-1;
while(i<=j){
if(numbers[i]<=numbers[j]){
j--;
}else if(numbers[i]>numbers[j]){
i++;
}
}
return numbers[i];
}
}
//方法三:分治(减治,分治的特殊情况), 因为分治只有在排好序之后才能分治
>> 这个是带符号右移
>>> 这个是无符号右移
public class Solution {
// [3, 4, 5, 1, 2]
// [1, 2, 3, 4, 5]
// 不能使用左边数与中间数比较,这种做法不能有效地减治
// [1, 2, 3, 4, 5]
// [3, 4, 5, 1, 2]
// [2, 3, 4, 5 ,1]
public int minArray(int[] numbers) {
int len = numbers.length;
if (len == 0) {
return 0;
}
int left = 0;
int right = len - 1;
/**
这个while处理的是旋转之后的数组;
如果没有旋转说明有序,直接返回numbers[left]即可。
*/
while (left < right) {
int mid = (left + right) >>> 1;
if (numbers[mid] > numbers[right]) {
// [3, 4, 5, 1, 2],mid 以及 mid 的左边一定不是最小数字
// 下一轮搜索区间是 [mid + 1, right]
left = mid + 1;
} else if (numbers[mid] == numbers[right]) {
// 只能把 right 排除掉,下一轮搜索区间是 [left, right - 1]
right = right - 1;
} else {
// 此时 numbers[mid] < numbers[right]
// mid 的右边一定不是最小数字,mid 有可能是,下一轮搜索区间是 [left, mid]
right = mid;
}
}
// 最小数字一定在数组中,因此不用后处理
return numbers[left];
}
}
//方法四:也有一个比较狗的方法
直接使用Array.sort(numbers),排序之后直接取第一个 numbers[0]
11[2].员工按年龄排序
对公司的所有员工按年龄排序,员工大约有几万人。
要求:时间复杂度O(N),可以使用辅助空间。
代码实现:
public class SortAges {
static int[] sortAges(int ages[],int length){
if(ages.length<0){
return new int[0];
}
//辅助空间,年龄范围
int[] helpSpace = new int[100];
for (int i = 0; i < ages.length; i++) {
if(0<ages[i] && ages[i]<100){
helpSpace[ages[i]]++;
}else {
System.out.println("这里可以抛一个异常,超出年龄范围!");
}
}
int index = 0;
for (int i = 0; i < helpSpace.length; i++) {
for (int j = 0; j < helpSpace[i]; j++) {
ages[index] = i;
index++;
}
}
return ages;
}
public static void main(String[] args) {
int[] ages = {1,3,1,5,10,50,12,11,30,50,12,10,44,34,44};
System.out.println(Arrays.toString(sortAges(ages, ages.length)));
}
}
运行结果:
[1, 1, 3, 5, 10, 10, 11, 12, 12, 30, 34, 44, 44, 50, 50]