求组合数 蓝桥杯集合的分割;
static int mod = 1000000000 + 7;
static int N = 1010;
//求
static long [][] arr=new long[N][N]; //需要开一个long
static {
for (int i = 0; i < N; i++) {
for (int j = 0; j <= i; j++) {
if (j== 0) {
arr[i][j] = 1;
} else {
arr[i][j] = (arr[i-1][j]+arr[i-1][j-1])%mod;
}
}
}
}
质数的一些性质
任何一个大于1的数都可以表示为一个质数的n倍;
public class 线性筛 {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
int n=scanner.nextInt();
boolean [] isPrime=aishishai(n);
for (int i = 0; i <=n; i++) {
if (isPrime[i]){
System.out.print(i+" ");
}
}
}
public static boolean[] aishishai(int n){
boolean [] isPrime=new boolean[n+1];//创建一个n+1长度的数组
Arrays.fill(isPrime,true);
isPrime[0]=false;
isPrime[1]=false;
for (int i = 2; i*i<=n; i++) { //这边也是根号n
if (isPrime[i]){
for (int j = i*i; j <=n ; j+=i) { //2*i 3*i 4*i
//当 i = 2 时,isPrime[2] 为 true,将从 2*2 = 4 开始的所有偶数标记为 false:
// [false, false, true, true, false, true, false, true, false, true,
// false, true, false, true, false, true, false, true, false, true,
// false, true, false, true, false, true, false, true, false, true, false, true]
isPrime[j]=false;
}
}
}
return isPrime;
}
}
时间复杂度 O(n log(log n))。
21的阶乘就已经超过了long类型;
二分查找的基础模板
在一共有序的数组中寻找一个数字,用二分查找的方式
采用的是左闭右闭得模式,while里面是小于等于
int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 1; //左闭右闭
while(left <= right) {
int mid = left + (right - left) / 2;//防止结果溢出
if(nums[mid] == target)
return mid;
else if (nums[mid] < target)
left = mid + 1; // 注意
else if (nums[mid] > target)
right = mid - 1; // 注意
}
return -1;
}
二分查找还具有其他得作用,可以查找左边界和右边界
寻找左边界得二分搜索左闭右闭的写法
int left_bound(int[] nums, int target) {
if (nums.length == 0) return -1;
int left = 0, right = nums.length;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
// 当找到 target 时,收缩右侧边界
right = mid;
} else if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid;
}
}
return left;
}
二分查找应用实际的题目,寻找左边界
Leetcode 1011在D天内送达包裹的能力;
一般用来判断元素在集合中是否出现过,常用的哈希的方法有 数组 set集合 map集合
leetcode 1; 用map集合来存储出现的元素,如果target-nums[i]在map中出现了,那么就找出来了nums[i]+nums[j]=target;
数组做映射 lt,有效字母的异位词,判断一个字母是否在另一个字母里面全部都出现过,
首先遍历第一个字母,用的是records[s.charAt(i)-‘a’]++,索引是对应的字母,索引对应的值是对应出现的次数。然后再遍历另一个字符串将出现的–,最后遍历这个数组;
用set集合来做映射,求两个数组之间的交集,一共字母可能出现了多次,如何解决呢,应该用set,遍历第一个字符串,添加到set1中,遍历第二个,如果set1中有那么就添加到set2中去,再将set2转为数组即可;
例题删除数组中重复的元素,需要原地删除,不能创建一个新的数组
slow=0,fast=0;
fast<nums.length
快指针进行移动,如果slow指针和fast指针对应的值不相等,需要往前移动slow指针,并且fast的值需要赋值给slow;
列题 移除数组中的元素,需要原地进行移除,想要时间复杂度变得很小如何去做呢?
left=0,right=nums.length;
left<right; 如果左边的值等于了val,将右边的值赋值给左边,同时right--;
左边的值不等于右边就是left不断地++;
处理字符串有一个叫做中心扩散法则,
class Solution {
public String longestPalindrome(String s) {
//最长回文的字串 中心扩散法则
int len = s.length();
if (len < 2) return s;
int[] res = new int[2];
int maxLeb = 0;
for (int i = 0; i < s.length(); i++) {
int odd[] = centerSpread(s, i, i);
int[] even = centerSpread(s, i, i + 1);
int[] max = odd[1] > even[1] ? odd : even;
if (max[1] > maxLeb) {
res = max;//将最大的赋值给res
maxLeb = max[1];
}
}
//res[0]是左边界 res[1]是对应的长度;
return s.substring(res[0], res[0] + res[1]);
}
public int[] centerSpread(String s, int left, int right) {
int len = s.length();
while (left >= 0 && right < len) {
if (s.charAt(left) == s.charAt(right)) {
left--;
right++
} else {
break;
}
}
//索引1是对应的坐标,索引二是对应的长度;
return new int[]{left + 1, right - left - 1}
}
}
什么时候应该使用优先队列?
求前k个元素.... 不断利用高位元素 求中位数
优先队列的模板题 leetcode 973
class Solution {
public int[][] kClosest(int[][] points, int k) {
PriorityQueue<long[]> queue =new PriorityQueue<>((a,b)->Long.compare(b[0],a[0]));
//比较的就是距离远点的平方; //比较规则的时候,需要使用long的包装类
for (int i = 0; i < points.length; i++) {
int []cur=points[i]; //当前数组
queue.add(new long[]{1L*cur[0]*cur[0]+cur[1]*cur[1],1l*i});
//把对应的距离 和索引都加到数组中去,数组在加到队列中去
if (queue.size()>k){
//寻找k个元素,如果大于了k,就需要讲小的进行返回,规则就是小的在·前
queue.poll();
}
}
int [][]ans=new int[k][];
int p=0;
while (!queue.isEmpty()) {
ans[p++] = points[(int)queue.poll()[1]];
}
return ans;
}
}
//优先队列就是可以根据自己的需要对元素进行排序,如果排序的规则比较复杂可以定义一个类来实现规则
public class Seg implements Comparable<Seg>{
int len,l,r;
public Seg(int len, int l, int r) {
this.len = len;
this.l = l;
this.r = r;
}
@Override
public int compareTo(Seg o) {
if (len==o.len){
return l-o.l; //返回一共数,升序排序
}else {
//长度不等,就看谁的长度大
return o.len-len;//进行降序排序
}
}
}
并查集模板,并查集有三个步骤 :1初始化,每一个节点的父节点都是自己
2找到根节点,需要进行路径压缩,将所有子节点都指向一个父节点
3联合,找到两个节点的父节点,将一个节点的父节点指向另一个节点
题目(244条消息) 【蓝桥杯】 历届试题 合根植物(并查集)_csdn_theSerein的博客-CSDN博客
public class BING {
static int fa[];
public static void main(String[] args) {
int n ,m,x,y;
Scanner scanner =new Scanner(System.in);
n=scanner.nextInt();
m=scanner.nextInt();
fa=new int[n+1];
init(n);
for (int i = 1; i <=m; i++) {
//自身指向自己的节点
x=scanner.nextInt();
y=scanner.nextInt();
union(x,y);
}
int q=scanner.nextInt();
for (int i = 0; i < q; i++) {
if (find(scanner.nextInt())!=find(scanner.nextInt())){
System.out.println("NO");
}else {
System.out.println("YES");
}
}
}
//路径压缩的代码
static void init(int n){
for (int i = 1; i <=n; i++) {
fa[i]=i;
}
}
static int find(int i){
if (fa[i]==i){ //如果父节点是自身的话,直接返回就行了
return i;
}
else{
fa[i]=find(fa[i]);//将i的父节点加入进来,进行递归
return fa[i];//是i的父节点
}
}
//通过这一段代码,将所有的节点都指向了一个父节点
static void union(int i,int j){
int i_fa=find(i); //找到对应的节点
int j_fa=find(j);//
fa[i_fa]=j_fa;//将节点进行合并操作
}
}
bfs求无权图的单元最短路径。