1.数轴上从左到右有n各点a[0], a[1], ……,a[n -1],给定一根长度为L的绳子,求绳子最多能覆盖其中的几个点
(1)右侧端点来到每一个点能覆盖多少
// 长度为L的绳子最多覆盖几个点,请保证arr有序
public static int maxPoint(int[] arr, int L) {
if(arr==null||arr.length==0){
return 0;
}
int numMax=Integer.MIN_VALUE;
for(int right=0;right<arr.length;right++){
int value=arr[right]-L;
int left=nearestIndex(arr,right,value);
int max=right-left+1;
numMax=Math.max(max,numMax);
}
return numMax;
}
// 在arr[0..R]范围上,找满足>=value的最左位置(二分)
public static int nearestIndex(int[] arr, int R, int value) {
int l=0;
int mid=(l+R)/2;
while(l<R){
if(arr[mid]>=value){
R=mid;
}else{
l=mid+1;
}
mid=(l+R)/2;
}
return mid;
}
(2)滑动窗口:L来到一个点,让R往右走,且LR的距离不超过5
public static int maxPoint2(int[] arr, int L){
if(arr==null||arr.length==0){
return 0;
}
int maxNum=Integer.MIN_VALUE;
for(int l=0;l<arr.length;l++){
int r=l;
while(r<arr.length&&arr[r]-arr[l]<=L){ //注意条件顺序不能反
int num=r-l+1;
maxNum=maxNum>num?maxNum:num;
r++;
}
}
return maxNum;
}
2.小虎去买苹果,商店只提供两种类型的塑料袋,每种类型都有任意数量。1.能装下6个苹果的袋子,2.能装下8个苹果的袋子。小虎可以自由使用两种袋子来装苹果,但是小虎有强迫症,他要求自己使用的袋子数量必须最少,且使用的每个袋子必须装满。给定一个正整数N,返回至少使用多少袋子。如果N无法让使用的每个袋子必须装满,返回-1。
(1)暴力解法:先尽量用8类型的袋子,再用6类型的袋子,且剩余的苹果如果大于24,则说明无解
public static int minBags(int apple) {
if(apple<0){
return -1;
}
int bag8=apple/8;//8类型的袋子
for(int i=bag8;i>=0;i--){//8类型的袋子依次递减
int rest= apple- i*8;//剩余的苹果
if(rest>24){
return -1;
}
if(rest%6==0){//如果能被6类型的袋子装下,则返回现在的袋子总数
return i+rest/6;
}
}
return -1;
}
(2)打表法:先用1-100枚举一下,找出规律,直接计算
public static int minBagAwesome(int apple) {
if(apple%2==1){
return -1;
}
if(apple==0){
return 0;
}
if(apple==2||apple==4||apple==10){
return -1;
}
if(apple==6||apple==8){
return 1;
}
if(apple==12||apple==14||apple==16){
return 2;
}
//前面的都是特例,后边是到18之后,8个为一组
return (apple-18)/8+3;
}
3.牛牛有一些排成一行的正方形。每个正方形已经被染成红色或者绿色。牛牛现在可以选择任意一个正方形然后用这两种颜色的任意一种进行染色,这个正方形的颜色将会被覆盖。牛牛的目标是在完成染色之后,每个红色R都比每个绿色G距离最左侧近。牛牛想知道他最少需要涂染几个正方形。
如样例所示: s = RGRGR
我们涂染之后变成RRRGG满足要求了,涂染的个数为2,没有比这个更好的涂染方案。
(1)暴力解法:左侧全为R,右侧全为G
// RGRGR -> RRRGG
public static int minPaint(String s) {
if(s==null||s.length()<2){
return 0;
}
char[] chars = s.toCharArray();
int numMin=Integer.MAX_VALUE;
for (int i=-1;i<chars.length;i++){
int num=0;
for(int j=0;j<=i;j++){
if(chars[j]=='G'){
num++;
}
}
for(int k=i+1;k<chars.length;k++){
if(chars[k]=='R'){
num++;
}
}
numMin=Math.min(num,numMin);
}
return numMin;
}
(2)预处理数组:A数组统计0到i中G的个数,A数组统计i到N-1中R的个数,
public static int minPaint1(String s) {
if(s==null||s.length()<2){
return 0;
}
char[] chars = s.toCharArray();
int[] A=new int[chars.length];
/*A数组统计过程*/
A[0]=chars[0]=='G'?1:0;
for (int i = 1; i < A.length; i++) {
A[i]=A[i-1]+(chars[i]=='G'?1:0);
}
/*B数组统计过程*/
int[] B=new int[chars.length];
B[chars.length-1]=chars[chars.length-1]=='R'?1:0;
for (int i = B.length-2; i >=0; i--) {
B[i]=B[i+1]+(chars[i]=='R'?1:0);
}
/*从前往后遍历过程,从-1(左侧元素个数为0)开始*/
int numMin=Integer.MAX_VALUE;
for (int i=-1;i<chars.length;i++){
if(i==-1){
numMin=Math.min(B[i+1],numMin);
}else if(i==chars.length-1){
numMin=Math.min(A[i],numMin);
}else {
int num=A[i]+B[i+1];
numMin=Math.min(num,numMin);
}
}
return numMin;
}
4.给定一个NM的矩阵matrix, 在这个矩阵中, 只有0和1两种值, 返回边框全是1的最大正方
形的边长长度。
例如:
0 1 1 1 1
0 1 0 0 1
0 1 0 0 1
0 1 1 1 1
0 1 0 1 1
其中, 边框全是1的最大正方形的大小为44, 所以返回4
(1)暴力解法
public static int maxBorderSize(int[][] m){
int N=m.length;
int M=m[0].length;
int maxBorder=Integer.MIN_VALUE;
for(int row=0;row<N;row++){
for (int col=0;col<M;col++){//遍历每一个点
for(int border=1;border<=Math.min(N-row,M-col);border++){//遍历这个点可能的边长,注意border<=Math.min(N-row,M-col)
boolean x1=true;//4个标志位,但凡有一条边不全为1,就置为false
boolean x2=true;
boolean x3=true;
boolean x4=true;
for(int i=0;i<border;i++){
if(m[row+i][col]!=1){
x1=false;
}
}
for(int i=0;i<border;i++){
if(m[row][col+i]!=1){
x2=false;
}
}
for(int i=0;i<border;i++){
if(m[row+i][col+border-1]!=1){
x3=false;
}
}
for(int i=0;i<border;i++){
if(m[row+border-1][col+i]!=1){
x4=false;
}
}
if(x1&&x2&&x3&&x4){
maxBorder=Math.max(maxBorder,border);
}
}
}
}
return maxBorder;
}
(2)预处理数组:right[]存储:每个位置i(包括自己)右边连续1的个数(别弄成右边有多少个1了)
down[]存储:每个位置i(包括自己)下边连续1的个数
public static int maxBorderSize1(int[][] m) {
int N = m.length;
int M = m[0].length;
int[][] right = getRight(m);
int[][] down = getDown(m);
int maxBorder = Integer.MIN_VALUE;
for (int row = 0; row < N; row++) {
for (int col = 0; col < M; col++) {
for(int border=1;border<=Math.min(N-row,M-col);border++){
if(right[row][col]>=border //注意是>=
&&down[row][col]>=border
&&right[row+border-1][col]>=border
&&down[row][col+border-1]>=border){
maxBorder=Math.max(maxBorder,border);
}
}
}
}
return maxBorder;
}
//得到right[][]
public static int[][] getRight(int[][] m){
int N = m.length;
int M = m[0].length;
int right[][]=new int[N][M];
for(int row=N-1;row>=0;row--){
right[row][M-1]=(m[row][M-1]==1?1:0);
for(int col=M-2;col>=0;col--){
if(m[row][col]==1){
right[row][col]=right[row][col+1]+1;//当前位置为1,才会考虑右侧连续1的个数
}else{
right[row][col]=0; //当前位置为0,right[当前位置]直接置0
}
}
}
return right;
}
//得到down[][]
public static int[][] getDown(int[][] m){
int N = m.length;
int M = m[0].length;
int down[][]=new int[N][M];
for(int col=0;col<=M-1;col++){
down[N-1][col]=(m[N-1][col]==1?1:0);
for(int row=N-2;row>=0;row--){
if(m[row][col]==1){
down[row][col]=down[row+1][col]+1;
}else{
down[row][col]=0;
}
}
}
return down;
}
5.已知一个函数f可以等概率的得到1-5间的随机数,怎么得到概率的得到1-7的随机数
/*等概率得到1-5*/
public static int _1To5(){
return (int) (Math.random()*5+1);
}
/*把等概率得到的1-5转化为0和1*/
public static int _0_or_1(){
int res=0;
do{
res=_1To5();
}while(res==3);
return res<3?0:1;
}
/*等概率得到1-7*/
public static int _1To7(){
int res=0;
do{
res=(_0_or_1()<<2)+(_0_or_1()<<1)+(_0_or_1()<<0);
}while(res==7);//7最少能用3位二进制表示,但是要的是0-6,所以res=7时继续投
return (int)res+1;
}
6.已知一个函数f可以等概率的得到13-21间的随机数,怎么得到概率的得到30-59的随机数
/*等概率得到13-21*/
public static int rand13to21(){
return (int)(Math.random()*9+13);
}
/*把等概率得到的13-21转化为0和1: 13,14,15,16, 17, 18,19,20,21 小于17为0,大于为1*/
public static int rand0or1(){
int res=0;
do{
res=rand13to21();
}while(res==17);
return (int)res<17?0:1;
}
public static int rand30to59(){
int res=0;
do{
res=(rand0or1()<<4)+(rand0or1()<<3)+(rand0or1()<<2)+(rand0or1()<<1)+(rand0or1());
}while(res>29);//29最少能用5位二进制表示,但是要的是0-29,所以res>29时继续投
return (int)res+30;
}
7.给定一个函数f,以p概率返回0,以1-p概率返回1。请加工出等概率返回0和1的函数g
/*以p的概率返回0或1*/
public static int p01(){
double p=0.7;
return (int)(Math.random()<0.7?0:1);
}
/*00=0重做,11=3重做,01=1----返回0,10=2----返回1*/
public static int rand_0_1(){
int res=0;
do{
res=(p01()<<1)+p01();
}while(res==0||res==3);
return res==1?0:1;
}
8.n个结点下,可构成多少种不同形态的二叉树
(1)暴力递归
public static int process(int n){
if(n<0){
return 0;
}
if(n==0){
return 1;
}
if(n==1){
return 1;
}
if(n==2){
return 2;
}
int res=0;
for(int leftNum=0;leftNum<=n-1;leftNum++){//左树的节点从0到n-1的情况
int left=process(leftNum);//左树有多少种
int right=process(n-leftNum-1);//右树有多少种
res+=left*right;//总共有多少种
}
return res;
}
(2)动态规划
public static int process1(int n){
if(n<0){
return 0;
}
if(n<2){
return 1;
}
int dp[]=new int[n+1];
dp[0]=1;
for(int i=1;i<=n;i++){//节点个数,从1到n
for (int j=0;j<=i-1;j++){//当前节点个数下,左树的节点个数递增
dp[i]+=dp[j]*dp[i-j-1];
}
}
return dp[n];
}
9.一个完整的括号字符串定义规则如下:
1、空字符串是完整的。
2、如果s是完整的字符串,那么(s)也是完整的。
3、如果s和t是完整的字符串,将它们连接起来形成的st也是完整的。
例如,"(()())", ““和”(())()“是完整的括号字符串,”())(”, “()(” 和 ")"是不完整的括号字符串。
牛牛有一个括号字符串s,现在需要在其中任意位置尽量少地添加括号,将其转化为一个完整的括号字符串。请问牛牛至少需要添加多少个括号。
public static int need(String str){
char[] chars = str.toCharArray();
int count=0;
int ans=0;//多的右括号个数
for(int i=0;i<chars.length;i++){
if(chars[i]=='('){
count++;
}else if(chars[i]==')'){
count--;
if(count<0){//当前右括号再也没有左括号匹配了
ans++;
count=0;
}
}
}
return ans+count;//若count最终大于0的话,说明左括号多了
}