a^b = c
则b= c^a
a = c^b
两种方法,第二种方法相等于第一种的加速寻找最大的,用了前缀树,用了32位补码相关知识
public class MaxEor {
public static int maxXorSubarray1(int[] arr){
if(arr == null || arr.length == 0){
return 0;
}
int[] eor = new int[arr.length];
eor[0] = arr[0];
for (int i = 0; i < arr.length; i++) {
eor[i] = eor[i-1] ^arr[i];
}
//上述代码求出了0...1
// 0...2 0...3 ... 的异或和
int max = Integer.MIN_VALUE;
//下面代码求的是0...j 1...j 2...j 3...j 根据异或和的性质i...j的异或和是eor[i-1]^eor[j]
for(int j = 0; j<arr.length;j++){
for (int i = 0; i <= j; i++) {
max = Math.max(max,i==0?eor[j]:eor[j]^eor[i-1]);
}
}
return max;
}
public static class Node{
public Node[] nexts = new Node[2];
}
public static class NumTrie{
public Node head = new Node();
//把newNum加入前缀树
//num是一个32位
public void add(int newNum){
Node cur = head;
for(int move = 31;move>=0;move--){
int path = ((newNum>>move)&1);//拿到第move位 只有0或者1
//无路新建 右路复用
cur.nexts[path] = cur.nexts[path] == null ? new Node():cur.nexts[path];
cur = cur.nexts[path];
}
}
//该结构收集一票数字,并且建好了前缀树
//sum 和谁 ^ 最大的结果(把结果返回)
public int maxXor(int sum){
Node cur = head;
int res= 0;
for(int move = 31;move>=0;move--){
//参数sum第move位是多少
int path = (sum >> move) & 1;
//贪心策略,如果是最高位,和原来一样,因为这样得到的是正数
// ,如果不是最高位,取反,因为异或后是1
int best = move == 31 ? path : (path^1);
//收集从开始到当前位异或后的结果
res |= (path ^ best) << move;
cur = cur.nexts[best];
}
return res;
}
}
public static int maxXorSubarray2(int[] arr){
if(arr == null || arr.length == 0){
return 0;
}
int max = Integer.MAX_VALUE;
int eor = 0;
NumTrie numTrie = new NumTrie();
numTrie.add(0);//一个数也没有 异或和是0
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i]; //是0...i的异或和
max = Math.max(max,numTrie.maxXor(eor));
numTrie.add(eor);//只增加0...i的异或和,因为其他的都可以通过0...i获得 比如i...j的,,可以通过0...i-1,和0...j的异或和获得
}
return max;
}
}
给定一个数组,对中间位置任意划分,最多能划分出多少个异或和为0的子数组
思路:假设答案法
蜜汁题目 理解不了。有机会再看
public class ExpressionNumber {
public static boolean isVaild(char[] exp){
if((exp.length & 1) == 0){
return false;
}
for (int i = 0; i < exp.length; i+=2) {
if((exp[i] != '1') && (exp[i]!='0')){
return false;
}
}
for (int i = 1; i < exp.length; i+=2) {
if((exp[i] != '&') && (exp[i] != '|') && (exp[i]!='^')){
return false;
}
}
return true;
}
public static int num1(String express,boolean desired){
if (express == null || express.equals("")) {
return 0;
}
char[] exp = express.toCharArray();
if(!isVaild(exp)){
return 0;
}
return f(exp,desired,0,exp.length-1);
}
public static int f(char[] exp,boolean desired,int L,int R){
if(L == R){
if(exp[L] == '1'){
return desired?1:0;
}else {
return desired?0:1;
}
}
//略
int res = 0;
if(desired){
for (int i = L+1; i < R; i+=2) {
switch (exp[i]){
case '&':
res+=f(exp,true,L,i-1)*f(exp,true,i+1,R);
}
}
}
return res;
}
}
public class JumpGame {
public static int jump(int[] arr){
if(arr == null || arr.length == 0){
return 0;
}
int step = 0;
int cur = 0;
int next = 0;
for (int i = 0; i < arr.length; i++) {
if(cur < i){
step++;
cur = next;
}
next = Math.max(next,i + arr[i]);
}
return step;
}
}
str中 至少切几刀,都是回文
public class PMinParts {
public static int minParts(String s){
if(s == null || s.length() == 0){
return 0;
}
if(s.length() == 1){
return 1;
}
char[] str = s.toCharArray();
int N = str.length;
boolean[][] isP = new boolean[N][N];
for (int i = 0; i < N; i++) {
isP[i][i] = true;
}
for (int i = 0; i < N - 1; i++) {
isP[i][i+1] = str[i] == str[i+1];
}
for(int row = N-1;row >=0;row--){
for(int col = row + 2;col < N;col++){
isP[row][col] = str[row] == str[col] && isP[row+1][col-1];
}
}
//isP[i][j]代表[i,j]位置是否是回文串
int[] dp = new int[N+1];
for(int i = 0;i <= N;i++){
dp[i] = Integer.MAX_VALUE;//找最小值
}
dp[N] = 0;
//dp[i]代表从i开始到最后 回文串最少切几刀
for (int i = N-1; i >= 0 ; i++) {
for(int end = i;end<N;end++){
if(isP[i][end]){
dp[i] = Math.min(dp[i],i+dp[end+1]);
}
}
}
return dp[0];
}
}