2022-4-21 二分查找
给定字符串 s 和 t ,判断 s 是否为 t 的子序列。
字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。
进阶:
如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?
1 class Solution { 2 public boolean isSubsequence(String s, String t) { 3 int l=0; 4 for (int i=0;i<s.length();i++){ 5 while (l<t.length()&&s.charAt(i)!=t.charAt(l)){ 6 l++; 7 } 8 if (l<t.length()){ 9 l++; 10 continue; 11 } 12 else return false; 13 } 14 return true; 15 } 16 }
思路:指针搜索。
f(x) 是 x! 末尾是 0 的数量。回想一下 x! = 1 * 2 * 3 * ... * x,且 0! = 1 。
- 例如,
f(3) = 0,因为3! = 6的末尾没有 0 ;而f(11) = 2,因为11!= 39916800末端有 2 个 0 。
给定 k,找出返回能满足 f(x) = k 的非负整数 x 的数量。
1 class Solution { 2 public int preimageSizeFZF(int k) { 3 // f(x)应该是一个非递减函数 4 // 答案就是左右边界的差 5 //二分查找左右边界 6 // x取到5000000000L k基本上为10^9 7 long left=0L,right=5000000000L; 8 // 左边界 9 while (left<right) { 10 long mid=(left+right)/2; 11 if ((int)f(mid)>k){ 12 right=mid; 13 }else if ((int)f(mid)<k){ 14 left=mid+1; 15 }else { 16 right=mid; 17 } 18 System.out.println(left+" "+right); 19 } 20 long left_bound=left; 21 left=0L; 22 right=5000000000L; 23 // 右边界,取到右边界必须相等。 24 while (left<=right) { 25 long mid=(left+right)/2; 26 if ((int)f(mid)==k){ 27 left=mid+1; 28 }else if((int)f(mid)<k){ 29 left=mid+1; 30 }else{ 31 right=mid-1; 32 } 33 //System.out.println(left+" "+right); 34 } 35 long right_bound=right; 36 //System.out.println(left_bound+" "+right_bound); 37 //System.out.println(f(left_bound)+" "+f(right_bound)); 38 //System.out.println(f(left_bound-1)+" "+f(right_bound+1)); 39 if (left_bound<=right_bound+1) return (int)(right_bound-left_bound+1); 40 else return 0; 41 42 43 } 44 45 46 public long f(long x){ 47 // 因数 2 5 相乘才会有0 48 // 且2 的数量肯定比5多 49 // fx为1~x中 5的因数的数量 50 long res=0L,pow=5L; 51 while (x>=pow){ 52 res+=(x/pow); 53 pow*=5; 54 } 55 return res; 56 } 57 }
思路:二分搜索上下边界。具体思路见注释。
浙公网安备 33010602011771号