2021-6-2剑指笔记00
Posted 轻舟一曲
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-6-2剑指笔记00相关的知识,希望对你有一定的参考价值。
笔记00
_01_最小的k个数
输入整数数组 arr
,找出其中最小的 k
个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:
输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:
输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:
0 <= k <= arr.length <= 10000
0 <= arr[i] <= 10000
package LeetCode;
import org.junit.Test;
import java.util.Arrays;
import java.util.PriorityQueue;
public class _01_最小的k个数
/*
对于经典的TopK问题,有四种通用解决方法:
1.快排
2.堆。Java中有现成的PriorityQueue
3.二叉搜索树
4.数据范围有限的话直接计数
* */
//1.快排 O(N)
//(int)(Math.random()*(end-start+1)+start); [start,end]
public int quick(int[] nums,int s,int e)
// if (s>=e) return s;
int i=s;
int j=e;
int index=nums[e];
int temp=0;
while (i<j)
while (nums[i]<index&&i<j) i++;
while (nums[j]>=index&&i<j) j--;//犯错点:少了等于号
temp=nums[i];
nums[i]=nums[j];
nums[j]=temp;
//while接触,ij相遇,找到最后一个值的正确位置
nums[e]=nums[i];
nums[i]=index;
return i;
public int TopK;
public void quickSearch(int[] nums,int s,int e)
int par=quick(nums,s,e);
if (par==TopK-1) return;
if (par>TopK-1)
quickSearch(nums,s,par-1);
else
quickSearch(nums,par+1,e);
public int[] getLeastNumbers(int[] arr, int k)
arr= new int[]3, 2, 1;
k=2;
TopK=k;
quickSearch(arr,0,arr.length-1);
return Arrays.copyOf(arr,k);
//2.堆。Java中有现成的PriorityQueue O(NlogK)
//用一个容量为k的大根堆,该法适合大数据处理
public int[] getLeastNumbers2(int[] arr, int k)
if (k==0||arr.length==0) return new int[0];
PriorityQueue<Integer> queue = new PriorityQueue<>((v1,v2)->v2-v1);
for (int num : arr)
if(queue.size()<k)
queue.offer(num);
else if (num < queue.peek())
queue.poll();
queue.offer(num);
int[] res=new int[k];
int index=0;
for (Integer integer : queue)
res[index++]=integer;
return res;
_02_数据流中的中位数
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例 1:
输入:
[“MedianFinder”,“addNum”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]
示例 2:
输入:
[“MedianFinder”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]
限制:
最多会对 addNum、findMedian 进行 50000 次调用。
package LeetCode;
import org.junit.Test;
import java.util.PriorityQueue;
public class _02_数据流中的中位数
public PriorityQueue<Integer> min=null;
public PriorityQueue<Integer> max=null;
public void init()
min=new PriorityQueue<>();
max=new PriorityQueue<>((v1,v2)->v2-v1);
//平均分成两堆,左边最大值堆(都小于)右边最小值堆
public _02_数据流中的中位数()
init();
//[最大堆,最小堆]
public void addNum(int num)
//为实现平均分配,数据总数是偶数时插入最小堆,否则插入最大堆
if (((max.size()+min.size())&1)==0)//最小堆
//如果此时num比最大堆的一些数据要小怎么办?
if (max.size()>0&&num<max.peek())//与最大堆根值交换,如果有
min.offer(max.poll());
max.offer(num);
else //最大堆空
min.offer(num);
else //插入最大堆
//如果此时num比最小堆的一些数据还要大怎么办?
if (min.size()>0&&num>min.peek())
max.offer(min.poll());
min.offer(num);
else
max.offer(num);
public double findMedian()
int lSize=max.size();
int rSize=min.size();
if (rSize==0&&lSize==0) return -1;
else if (((rSize+lSize)&1)==1) return min.peek();
else return (double)(max.peek()+min.peek())/2;
_03_1到n整数中1的次数
输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
限制:
1 <= n < 2^31
package LeetCode;
import org.junit.Test;
import java.util.Arrays;
public class _03_1到n整数中1的次数
//方法一:求余 O(NlogN) 对于每个数字n,n有logN位
public int countDigitOne1(int n)
int times=0;
int num=0;
for (int i = 1; i <= n; i++)
num=i;
while (num!=0)
if (num%10==1) times++;
num/=10;
return times;
@Test
public void test()
System.out.println(countDigitOne(12));
/*
方法二数学规律:主要理解每次去掉最高位进行递归,而且每次是隔一位而已
首先求最高位1的个数:
去掉最高位:求剩余位1的个数用排列组合
* */
public int countDigitOne(int n)
if (n<=0) return 0;
strN=Integer.toString(n).toCharArray();
len=strN.length;
return numberOf1(0);
public char[] strN;
public int len;
public int numberOf1(int curr)
//后序遍历
if (curr>len-1)
return 0;
int first=strN[curr]-'0';
//考虑个位数
if (curr==len-1&&first==0) return 0;
if (curr==len-1&&first>0) return 1;
//假设当前统计数是21345
//数字1,0000到1,9999中1出现在第一位的次数
int numFirstDigit=0;
if (first>1)
numFirstDigit= (int) Math.pow(10,len-1-curr);
else if (first==1)
int parLen=len-1-(curr+1)+1;//剩下的位数
for (int i = curr+1; i <= len-1; i++)
numFirstDigit+=(strN[i]-'0')*Math.pow(10,parLen-1);
parLen--;
numFirstDigit+=1;
//计算1346-21345中1除了在最高位之外出现的次数,排列组合即可
//可以划分为两段,1346-11345(相当于0-9999) 和 11346-21345(相当于0-9999)
int numOtherDigits= (int) (first*(len-1-curr)*Math.pow(10,len-2-curr));
//统计1-1345中的1的个数,后序遍历,递归
int numRecursive=numberOf1(curr+1);
return numFirstDigit+numOtherDigits+numRecursive;
_04_数字序列中某一位的数字
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
限制:
0 <= n < 2^31
package LeetCode;
import org.junit.Test;
public class _04_数字序列中某一位的数字
@Test
public void test()
int n=findNthDigit(1000000000);
System.out.println((long) (9*Math.pow(10,9)));
System.out.println((long) (9*Math.pow(10,10)));//900 0000 0000
System.out.println((int) (9*Math.pow(10,9)));
System.out.println((int) (9*Math.pow(10,10)));//2147483647
long a=9000000000L;
System.out.println((long) 3 *a );
public int findNthDigit(int n)
if (n<0) return -1;
int digits=1;//位数
while (true)
//统计m位数有几个
long numsDig=countDig(digits);
//结束条件:知道要找的那个数在m位数之中
if (n<(long)digits*numsDig)
return find(n,digits);
n-=digits*numsDig;
digits++;
/*
0-9:10个
10-99 :90个
100-999:900个
1000-9999:9000个
* */
public long countDig(int digits)
if (digits==1) return 10;
else return (long) (9*Math.pow(10,digits-1));
//811=3*270+1 100后的第270位370中的7
public int find(int n,int digits)
int number=firstDig(digits)+n/digits;
int toRight=digits-n%digits;//右数第xx位
for (int i=1;i<toRight;i++)
number/=10;
return number%10;
/*
m位数字的第1个数:
0
10
100
1000
* */
public int firstDig(int digits)
if (digits==1) return 0;
else return (int) Math.pow(10,digits-1);
_05_把数组排成最小的数
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: “102”
示例 2:
输入: [3,30,34,5,9]
输出: “3033459”
提示:
0 < nums.length <= 100
package LeetCode;
import com.sun.deploy.util.StringUtils;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
public class _05_把数组排成最小的数
@Test
public void test()
String[] res="43","12","2";
System.out.println();
/*
解题思路很简单:就是定义一个新的比大小规则,然后进行升序就好了 复杂度是O(NlogN)
证明则比较复杂
* */
public String minNumber(int[] nums)
if (nums==null||nums.length==0) return null;
String[] res=new String[nums.length];
int i=0;
for (int num : nums)
res[i++]=Integer.toString(num);
Arrays.sort(res,new Comparator<String>()
@Override
public int compare(String o1, String o2)
String s1=o1.concat(o2);
String s2=o2.concat(o1);
return s1.compareTo(s2);
);
StringBuilder builder=new StringBuilder();
for (String re : res)
builder.以上是关于2021-6-2剑指笔记00的主要内容,如果未能解决你的问题,请参考以下文章
剑指offer(C++)-JZ53:数字在升序数组中出现的次数(算法-搜索算法)