排序衍生
^运算符
^ 异或操作,理解为不进位相加 有交换率。 a^a=0 a^0=a
public static void sway(int[] arr,int i,int j){
if(i!=j){
arr[i]=arr[i]^arr[j];
arr[j]=arr[i]^arr[j];
arr[i]=arr[i]^arr[j];
}
}
找一个单数
一组数只有一个数出现一次,其他出现两次,找出这个数:
public static void main(String[] args) {
int[] ints = {2, 2, 4, 4, 6, 8, 99, 99, 6, 8, 43, 76, 43, 76, 111};
int med=0;
for (int a:ints){
med^=a;
}
System.out.println(med);
}
找两个个单数
一组数只有两个数出现一次,其他出现两次,找出这两个数:
public static void main(String[] args) {
int[] ints = {2, 2, 4, 4, 6, 8, 99, 99, 6, 8, 43, 76, 43, 76, 111,333};
int med=0;
for (int a:ints){
med^=a;
}
int rightOne=med&(~med+1);
int med1=0;
for (int a:ints){
if ((a&rightOne)== rightOne){
med1^=a;
}
}
System.out.println(med1);
System.out.println(med^med1);
}
基于归并排序的小数和
数组的每个值前比他本身小的和的总和。求数组的小数和
public static int mergeSortTest(int[] arr, int left, int right, int[] temp){
if(left<right){
int m=(left+right)/2;
return
mergeSortTest(arr,left,m,temp)+
mergeSortTest(arr,m+1,right,temp)+
mergeTest(arr,left,m,right,temp);
}
return 0;
}
private static int mergeTest(int[] arr, int left, int m, int right, int[] temp) {
int i=left;
int j=m+1;
int tempIndex=0;
int res=0;
while (i<=m&&j<=right){
res+=arr[i]<arr[j]?arr[i]*(right-j+1):0;
temp[tempIndex++]=arr[i]<arr[j]?arr[i++]:arr[j++];
}
while (i<=m)
temp[tempIndex++]=arr[i++];
while (j<=right)
temp[tempIndex++]=arr[j++];
System.arraycopy(temp, 0, arr, left, tempIndex);
return res;
}
二分衍生
查找极小值
该值比左右的值都小,如果是在数组两侧则只比较一点即可。 在无序数组中找到该极小值
public class Test{
public static void main(String[] args) {
System.out.println(limitMin(new int[]{235, 34,53, 53, 354, 454, 45, 65}, 0, 7));
}
public static int limitMin(int[] arr,int left,int right){
if(arr[left]<arr[left+1]){
return arr[left];
}else if (arr[right]<arr[right-1]){
return arr[right];
}
int med=(left+right)/2;
if(arr[med+1]>arr[med]){
return limitMin(arr,left,med);
}else {
return limitMin(arr,med,right);
}
}
}
链表衍生
判断链表的回文
package Test;
import java.util.Stack;
public class Test {
public static void main(String[] args) {
LinkedList list = new LinkedList();
list.add(1);
list.add(5);
list.add(3);
list.add(7);
list.add(3);
list.add(5);
list.add(1);
LinkedList list1 = new LinkedList();
list1.add(1);
list1.add(4);
list1.add(4);
list1.add(1);
System.out.println(IsTrue.isTrue_1(list.header));
System.out.println(IsTrue.isTrue_2(list.header));
System.out.println(IsTrue.isTrue_1(list1.header));
System.out.println(IsTrue.isTrue_2(list1.header));
System.out.println(IsTrue.isTrue_3(list1.header));
System.out.println(IsTrue.isTrue_3(list.header));
}
}
class IsTrue{
public static boolean isTrue_1(Node header){
if (header==null)throw new RuntimeException("空");
Node tail=header;
Stack<Node> stack = new Stack<>();
while (tail!=null){
stack.push(tail);
tail=tail.next;
}
tail=header;
while (tail!=null){
if (tail.num!=stack.pop().num)
return false;
tail=tail.next;
}
return true;
}
public static boolean isTrue_2(Node header){
if (header==null||header.next==null)return true;
Node slow=header;
Node quick=header;
while (quick.next!=null&&quick.next.next!=null){
slow=slow.next;
quick=quick.next.next;
}
slow=slow.next;
Stack<Node> nodes = new Stack<Node>();
while (slow!=null){
nodes.push(slow);
slow=slow.next;
}
slow=header;
while (!nodes.isEmpty()){
if (slow.num!=nodes.pop().num)
return false;
slow=slow.next;
}
return true;
}
public static boolean isTrue_3(Node header) {
if (header == null || header.next == null) return true;
Node node1 = header;
Node node2 = header;
while (node2.next != null && node2.next.next != null) {
node1 = node1.next;
node2 = node2.next.next;
}
node2 = node1.next;
node1.next = null;
Node node3;
while (node2 != null) {
node3 = node2.next;
node2.next = node1;
node1 = node2;
node2 = node3;
}
node2 = header;
node3 = node1;
boolean flag = true;
while (node2 != null&&node3!=null) {
if (node3.num!=node2.num){
flag=false;
break;
}
node3 = node3.next;
node2 = node2.next;
}
node3 = node1.next;
node1.next = null;
while (node3 != null) {
node2 = node3.next;
node3.next = node1;
node1 = node3;
node3 = node2;
}
return flag;
}
}
class LinkedList{
Node header;
public void add(int num){
if (header==null){
header=new Node(num,null);
return;
}
Node tail=header;
while (tail.next!=null){
tail=tail.next;
}
tail.next=new Node(num,null);
}
}
class Node{
int num;
Node next;
public Node(int num, Node next) {
this.num = num;
this.next = next;
}
}
复制随机指向的链表
package Test;
public class Test {
public static void main(String[] args) {
Node header=new Node(0);
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
Node node5=new Node(5);
header.next=node1;
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next= node5;
node1.rand=node4;
node3.rand=node2;
node5.rand=node1;
CopyLinkedList.copy_1(header);
CopyLinkedList.copy_2(header);
}
}
class CopyLinkedList{
public static Node copy_1(Node header){
if (header==null)return null;
HashMap<Node, Node> map = new HashMap<Node, Node>();
Node tail=header;
while (tail!=null){
map.put(tail,new Node(tail.value));
tail=tail.next;
}
tail=header;
while (tail!=null){
map.get(tail).next=map.get(tail.next);
map.get(tail).rand=map.get(tail.rand);
tail=tail.next;
}
return map.get(header);
}
public static Node copy_2(Node header){
if (header==null)return null;
Node tail=header;
Node n;
while (tail!=null){
n=tail.next;
tail.next=new Node(tail.value);
tail.next.next=n;
tail=n;
}
tail=header;
Node copyTail;
while (tail!=null){
n=tail.next.next;
copyTail=tail.next;
if (tail.rand!=null)
copyTail.rand=tail.rand.next;
tail=n;
}
Node copyHeader=header.next;
tail=header;
while (tail!=null){
n=tail.next.next;
copyTail=tail.next;
if (n!=null)
copyTail.next=n.next;
tail.next=n;
tail=n;
}
return copyHeader;
}
}
class Node{
int value;
Node next;
Node rand;
public Node(int value){
this.value=value;
}
}
三分链表
给定一个只将比该值小的节点放左边,大的放右边
class SEL{
public static Node sEL(Node header,int pivot){
Node head_1=null;
Node tail_1=null;
Node head_2=null;
Node tail_2=null;
Node head_3=null;
Node tail_3=null;
Node nextNode=null;
while (header!=null){
nextNode=header.next;
header.next=null;
if (header.num<pivot){
if (head_1==null){
head_1=header;
tail_1=header;
}else {
tail_1.next=header;
tail_1=tail_1.next;
}
}else if (header.num==pivot){
if (head_2==null){
head_2=header;
tail_2=header;
}else {
tail_2.next=header;
tail_2=tail_2.next;
}
}else {
if (head_3==null){
head_3=header;
tail_3=header;
}else {
tail_3.next=header;
tail_3=tail_3.next;
}
}
header=nextNode;
}
if (tail_1==null){
if (tail_2==null){
return head_3;
}else {
tail_2.next=head_3;
return head_2;
}
}else {
if (tail_2==null){
tail_1.next=head_3;
}else {
tail_1.next=head_2;
tail_2.next=head_3;
}
return head_1;
}
}
}
判断链表是否有环
判断链表是否有环,若有返回第一个入环节点 慢:1 快:2 若慢:1快3: 都入环时相差奇数步,且环节点数量为偶数则永不相交
都入环时相差奇数步说明每次差值减少2步,定在第一轮反超,此时差 环节点个数-1,若该值仍为奇数,那么第二轮也反超,故永不相遇
package Test;
public class Test {
public static void main(String[] args) {
Node header=new Node(0);
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
Node node5=new Node(5);
header.next=node1;
node1.next=node2;
node2.next=node3;
node3.next=node4;
node4.next=node5;
node5.next=node2;
System.out.println(HasCircle.hasCircle(header).num);
}
}
class HasCircle{
public static Node hasCircle(Node header){
if (header==null)return null;
boolean flag=false;
Node slow=header;
Node quick=header;
while (quick.next!=null&&quick.next.next!=null){
slow=slow.next;
quick=quick.next.next;
if (slow==quick){
flag=true;
break;
}
}
if (!flag)return null;
quick=header;
while (quick!=slow){
quick=quick.next;
slow=slow.next;
}
return quick;
}
}
class Node{
int num;
Node next;
public Node(int num){
this.num=num;
}
}
两个链表相交关系
class List{
public static Node getIntersectNode(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node loop1 = hasCircle(head1);
Node loop2 = hasCircle(head2);
if (loop1 == null && loop2 == null) {
return noLoop(head1, head2);
}
if (loop1 != null && loop2 != null) {
return bothLoop(head1, loop1, head2, loop2);
}
return null;
}
private static Node hasCircle(Node header){
if (header==null)return null;
boolean flag=false;
Node slow=header;
Node quick=header;
while (quick.next!=null&&quick.next.next!=null){
slow=slow.next;
quick=quick.next.next;
if (slow==quick){
flag=true;
break;
}
}
if (!flag)return null;
quick=header;
while (quick!=slow){
quick=quick.next;
slow=slow.next;
}
return quick;
}
private static Node noLoop(Node head1, Node head2) {
if (head1 == null || head2 == null) {
return null;
}
Node cur1 = head1;
Node cur2 = head2;
int n = 0;
while (cur1.next != null) {
n++;
cur1 = cur1.next;
}
while (cur2.next != null) {
n--;
cur2 = cur2.next;
}
if (cur1 != cur2) {
return null;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
}
private static Node bothLoop(Node head1, Node loop1, Node head2, Node loop2) {
Node cur1 = null;
Node cur2 = null;
if (loop1 == loop2) {
cur1 = head1;
cur2 = head2;
int n = 0;
while (cur1 != loop1) {
n++;
cur1 = cur1.next;
}
while (cur2 != loop2) {
n--;
cur2 = cur2.next;
}
cur1 = n > 0 ? head1 : head2;
cur2 = cur1 == head1 ? head2 : head1;
n = Math.abs(n);
while (n != 0) {
n--;
cur1 = cur1.next;
}
while (cur1 != cur2) {
cur1 = cur1.next;
cur2 = cur2.next;
}
return cur1;
} else {
cur1 = loop1.next;
while (cur1 != loop1) {
if (cur1 == loop2) {
return loop1;
}
cur1 = cur1.next;
}
return null;
}
}
}
class Node{
int value;
Node next;
public Node(int num){
this.value=num;
}
}
优先队列
持续输出中位数(堆/优先队列)
持续输入一个数,可以在任意时刻输出中位数。
- 构建两个堆,一个大堆,一个小堆,大堆放较小的元素,小堆放较大的元素
- 持续保持两个堆的元素个数差不超过1
- 超过1,将大堆中堆顶元素放进小堆或将小堆堆顶元素放进大堆。
- 这样中位数就一直只和两个堆的堆顶元素相关
class Tree {
private PriorityQueue<Double> little;
private PriorityQueue<Double> large;
public Tree() {
little = new PriorityQueue<>();
large = new PriorityQueue<>((o1, o2) -> Double.compare(o2, o1));
}
public void add(Double x) {
if (little.size() == 0 && large.size() == 0)
large.add(x);
else {
if (large.peek() < x)little.add(x);
else large.add(x);
if (little.size() - large.size() > 1)
large.add(little.poll());
else if (little.size() - large.size() < -1)
little.add(large.poll());
}
}
public Double getMed(){
if (little.size()-large.size()==0)
return (little.peek()+large.peek())/2;
else if (little.size()-large.size()>0)
return little.peek();
else return large.peek();
}
}
二叉树衍生
前中后横向遍历非递归实现
package Test;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Stack;
public class Test {
public static void main(String[] args) {
Node root=new Node(0);
Node node1=new Node(1);
Node node2=new Node(2);
Node node3=new Node(3);
Node node4=new Node(4);
Node node5=new Node(5);
root.left=node1;
root.right=node2;
node1.left=node3;
node1.right=node4;
node4.right=node5;
Tree.pre(root);
System.out.println();
Tree.inOrderUnRecur(root);
System.out.println();
Tree.posOrderUnRecur1(root);
System.out.println();
Tree.posOrderUnRecur2(root);
}
}
class Tree{
public static void pre(Node root){
System.out.print("pre-order: ");
if (root==null)return;
Stack<Node> stack = new Stack<>();
stack.push(root);
while (!stack.isEmpty()){
Node n=stack.pop();
System.out.print(n.value+" ");
if (n.right!=null){
stack.push(n.right);
}
if (n.left!=null){
stack.push(n.left);
}
}
}
public static void inOrderUnRecur(Node head) {
System.out.print("in-order: ");
if (head != null) {
Stack<Node> stack = new Stack<Node>();
while (!stack.isEmpty() || head != null) {
if (head != null) {
stack.push(head);
head = head.left;
} else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
System.out.println();
}
public static void posOrderUnRecur1(Node head) {
System.out.print("pos-order: ");
if (head != null) {
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
s1.push(head);
while (!s1.isEmpty()) {
head = s1.pop();
s2.push(head);
if (head.left != null) {
s1.push(head.left);
}
if (head.right != null) {
s1.push(head.right);
}
}
while (!s2.isEmpty()) {
System.out.print(s2.pop().value + " ");
}
}
System.out.println();
}
public static void posOrderUnRecur2(Node h) {
System.out.print("pos-order: ");
if (h != null) {
Stack<Node> stack = new Stack<Node>();
stack.push(h);
Node c = null;
while (!stack.isEmpty()) {
c = stack.peek();
if (c.left != null && h != c.left && h != c.right) {
stack.push(c.left);
} else if (c.right != null && h != c.right) {
stack.push(c.right);
} else {
System.out.print(stack.pop().value + " ");
h = c;
}
}
}
System.out.println();
}
public static void w(Node root){
if (root==null)return;
Deque<Node> deque=new ArrayDeque();
deque.add(root);
while (!deque.isEmpty()){
Node n=deque.poll();
System.out.println(n);
if (n.left!=null){
deque.add(n.left);
}
if (n.right!=null){
deque.add(n.right);
}
}
}
}
class Node{
int value;
Node left;
Node right;
public Node(int num){
this.value=num;
}
}
计算树每一层的最多节点个数
class Tree{
public static int fun_1(Node root) {
if (root == null) return 0;
Deque<Node> deque = new ArrayDeque();
HashMap<Node, Integer> map = new HashMap<Node, Integer>();
deque.add(root);
int floor=1;
int thisNum=0;
int maxNum = 0;
map.put(root,floor);
while (!deque.isEmpty()) {
Node n = deque.poll();
if (map.get(n)==floor){
thisNum++;
}else {
maxNum=Math.max(maxNum,thisNum);
thisNum=1;
floor++;
}
if (n.left != null) {
deque.add(n.left);
map.put(n.left,floor+1);
}
if (n.right != null) {
deque.add(n.right);
map.put(n.right,floor+1);
}
}
return Math.max(thisNum,maxNum);
}
public static int fun_2(Node root) {
if (root == null) return 0;
Node thisLastNode=root;
Node nextLastNode=null;
int maxNum=0;
int thisNum=0;
Deque<Node> deque = new ArrayDeque();
deque.add(root);
while (!deque.isEmpty()) {
Node n = deque.poll();
thisNum++;
if (n.left != null) {
deque.add(n.left);
nextLastNode=n.left;
}
if (n.right != null) {
deque.add(n.right);
nextLastNode=n.right;
}
if (n==thisLastNode){
thisLastNode=nextLastNode;
nextLastNode=null;
maxNum=Math.max(thisNum,maxNum);
thisNum=0;
}
}
return maxNum;
}
}
class Node{
int value;
Node left;
Node right;
public Node(int num){
this.value=num;
}
}
判断是搜索二叉树(套路题)
isBST_2递归套路:
class Tree{
private static int last=Integer.MIN_VALUE;
public static boolean isBST_1(Node head){
if (head==null){
return true;
}
if (!isBST_1(head.left))return false;
if (last>=head.value)return false;
else last=head.value;
return isBST_1(head.right);
}
public static returnType isBST_2(Node head){
if (head==null)return null;
returnType leftType= isBST_2(head.left);
returnType rightType= isBST_2(head.right);
int min=head.value;
int max=head.value;
boolean flag=true;
if (leftType!=null){
if (!leftType.isbst||leftType.max>=head.value)flag=false;
min=Math.min(leftType.min,head.value);
max=Math.max(leftType.max,head.value);
}
if (rightType!=null){
if (!rightType.isbst||rightType.min<=head.value)flag=false;
min=Math.min(rightType.min,head.value);
max=Math.max(rightType.max,head.value);
}
return new returnType(min,max,flag);
}
static class returnType{
boolean isbst;
int min;
int max;
private returnType(int min, int max, boolean flag){
this.min=min;
this.max=max;
this.isbst=flag;
}
}
}
class Node{
int value;
Node left;
Node right;
public Node(int num){
this.value=num;
}
}
判断是完全二叉树(套路题)
class Tree {
public static boolean isCBT(Node head) {
if (head == null) return true;
boolean flag = false;
Deque<Node> deque = new ArrayDeque<Node>();
deque.add(head);
while (!deque.isEmpty()) {
Node node = deque.pop();
if ((node.left == null && node.right != null)
||
(flag && (node.right != null || node.right != null)))
return false;
if (node.left != null) deque.add(node.left);
if (node.right != null) deque.add(node.right);
if (node.left == null || node.right == null) flag = true;
}
return true;
}
}
class Node {
int value;
Node left;
Node right;
public Node(int num) {
this.value = num;
}
}
判断是满二叉树(套路题)
递归套路:
class Tree {
public static boolean isF_1(Node head){
Data data = is_1(head);
return (1<<data.height)-1==data.nodeNum;
}
private static Data is_1(Node head){
if (head==null)return new Data(0,0);
Data lData=is_1(head.left);
Data rData=is_1(head.right);
int num=lData.nodeNum+rData.nodeNum+1;
int he=Math.max(lData.height,rData.height)+1;
return new Data(num,he);
}
public static boolean isF_2(Node head){
Data data = is_2(head);
return data != null;
}
private static Data is_2(Node head){
if (head==null)return new Data(0,0);
Data lData=is_2(head.left);
Data rData=is_2(head.right);
if (lData==null||rData==null)
return null;
if (lData.nodeNum!=rData.nodeNum||lData.height!=rData.height)
return null;
int num=lData.nodeNum+rData.nodeNum+1;
int he=lData.height+1;
return new Data(num,he);
}
static class Data{
int nodeNum;
int height;
boolean is;
public Data(int nodeNum,int height){
this.nodeNum=nodeNum;
this.height=height;
}
}
}
class Node {
int value;
Node left;
Node right;
public Node(int num) {
this.value = num;
}
}
判断是平衡树(套路题)
递归套路:
class Tree {
public static Data isAVL(Node head){
if (head==null)return new Data(0,true);
Data lData=isAVL(head.left);
Data rData=isAVL(head.right);
int height=Math.max(lData.height,rData.height)+1;
boolean flag=lData.isAVL&&rData.isAVL&&Math.abs(lData.height-rData.height)<=1;
return new Data(height,flag);
}
static class Data{
int height;
boolean isAVL;
public Data(int height ,boolean is){
this.height=height;
this.isAVL=is;
}
}
}
class Node {
int value;
Node left;
Node right;
public Node(int num) {
this.value = num;
}
}
树节点最远距离(套路题)
递归套路:
- 根据子树最大深度计算出经过当前节点的最长距离
- 向上传递子树和经过当前节点最长距离 的最大值
- 最长距离需要子树深度
- 所以递归数据包括最大距离和最大深度
class U {
public static Data maxLength(Node head){
if (head==null)return new Data(0,0);
Data ld=maxLength(head.left);
Data rd=maxLength(head.right);
int maxLen=Math.max(ld.maxHeight+rd.maxHeight+1,Math.max(ld.maxLen,ld.maxLen));
int maxHeight=Math.max(ld.maxHeight,rd.maxHeight)+1;
return new Data(maxLen,maxHeight);
}
private static class Data{
int maxLen;
int maxHeight;
private Data(int maxLen,int maxHeight){
this.maxLen=maxLen;
this.maxHeight=maxHeight;
}
}
}
最大快乐值(套路题)
递归套路:
- 最大值和每个节点是否去有关,就是取 当前节点不去(0)+子节点去或不去的最大值 和 当前节点去(happy)+子节点不去的最大值
- 每个节点的去和不去都会直接影响父类节点,间接影响祖宗节点。
- 只要递归传递该节点去和不去的最大值信息即可。
class U {
public static Data maxHappy(Node head){
if (head.nexts==null)return new Data(0,head.happy);
int lai=head.happy;
int bu=0;
for (Node node:head.nexts){
Data data = maxHappy(node);
lai+=data.maxBu;
bu+=Math.max(data.maxBu,data.maxLai);
}
return new Data(bu,lai);
}
private static class Data{
int maxBu;
int maxLai;
private Data(int maxBu,int maxLai){
this.maxBu =maxBu;
this.maxLai =maxLai;
}
}
}
class Node {
int happy;
Node[] nexts;
}
查找树中两个节点的最近共父类节点
- 该路径上不存在寻找的o1或o2,就回馈上一次递归null
- 路径上存在o1或o2,返回标记告诉上一次递归存在o1或o2
- 直到在某次递归时判断出左右路径都回馈了有o1或o2,就将该父节点返回
- 将返回的父节点以返回值的方式传给上一次递归直至结束递归。
class Tree {
public static Node ancestor(Node header, Node o1, Node o2) {
if (header == null || o1 == header || o2 == header) return header;
Node lNode = ancestor(header.left, o1, o2);
Node rNode = ancestor(header.right, o1, o2);
if (lNode != null && rNode != null)
return header;
return lNode != null ? lNode : rNode;
}
}
class Node {
int value;
Node left;
Node right;
public Node(int num) {
this.value = num;
}
}
查找后继结点
- 有右节点,右树上的最左节点
- 无右节点,递归寻找节点是父节点左节点的点
- 否则空
class Tree {
public static Node process(Node node){
if (node==null)return null;
if (node.right!=null)return leftLast(node.right);
Node parentTail=node.parent;
while (parentTail!=null&&parentTail.left!=node){
node=parentTail;
parentTail=parentTail.parent;
}
return parentTail;
}
private static Node leftLast(Node head){
while (head.left!=null)
head=head.left;
return head;
}
}
class Node {
int value;
Node left;
Node right;
Node parent;
public Node(int num) {
this.value = num;
}
}
折纸凹凸问题
上次每个折痕都有两个子折痕,上凹下凸,也就是二叉树节点都有一个凹左节点一个凸右节点。这些折痕的顺序就是二叉树的中序遍历。
class Tree {
public static void pre(int N){
pre(N,true);
}
private static void pre(int num,boolean down){
if (num==0)return;
pre(num-1,true);
System.out.print(down?"down ":"up ");
pre(num-1,false);
}
}
哈夫曼最小代价问题
class Tree {
public static int lessConsumer(int[] arr){
if (arr.length==1)return arr[0];
PriorityQueue<Integer> queue = new PriorityQueue<>();
for (int i : arr)
queue.add(i);
int sum=0;
while (queue.size()>1){
int num1=queue.poll();
int num2=queue.poll();
sum+=(num1+num2);
queue.add(num1+num2);
}
return sum;
}
}
暴力递归
N皇后(位运算)
class E {
public static int num(int num) {
if (num < 1 || num > 32) return 0;
int limit = num == 32 ? -1 : (1 << num) - 1;
return process(limit, 0, 0, 0);
}
private static int process(int limit, int coLim, int leftLim, int rightLim) {
if (limit == coLim) return 1;
int pos = limit & (~(coLim | leftLim | rightLim));
int res = 0, mostRightOne;
while (pos != 0) {
mostRightOne = pos & (~pos + 1);
pos = pos - mostRightOne;
res += process(limit, coLim | mostRightOne
, (leftLim | mostRightOne) << 1
, (rightLim | mostRightOne) >> 1);
}
return res;
}
}
字符串的全排列
- 我们通常都思路都是将所有字符依次放在最前面,例如ABC,第一位为A,B,C,然后判断第二位,那么我们如何在字符串中标记该字符已经被我们安排在前面了?
- 若我们使用下标的方式,那么在每次选择都会产生一个下标,这样会很乱。
- 于是我们可以通过将欲放在前面的字符就直接放在前面(将字符一次和后面的交换),用一个下标指引我们前面已经定了多少的元素。
- 但是若我们交换后在后续调用时,数据顺序已经打乱,我们可能会造成重复情况,所以我们在每次运行后再将数据交换变成原来位置。
- 但是当数据有重复字符时,会出现重复的全排列,这是我们就要判断交换的字符是否和之前交换的相同,若相同,就不用交换
class PB {
public static List<String> list=new ArrayList<>();
public static void process(String string){
char[] chars = string.toCharArray();
process(chars,0);
}
private static void process(char[] chars, int i){
if (i==chars.length){
list.add(new String(chars));
return;
}
boolean[] isVisited=new boolean[26];
for (int j=i;j<chars.length;j++){
if (!isVisited[chars[j]-'A']){
isVisited[chars[j]-'A']=true;
swap(chars,i,j);
process(chars,i+1);
swap(chars,i,j);
}
}
}
private static void swap(char[] chars,int i, int j) {
char c = chars[i];
chars[i]=chars[j];
chars[j]=c;
}
}
纸牌累计分数
class PB {
public static int win(int[] arr){
if (arr.length==0)return 0;
return Math.max(front(arr,0,arr.length-1), end(arr,0,arr.length-1));
}
private static int front(int[] arr,int left,int right){
if (left==right)return arr[left];
return Math.max(arr[left]+end(arr,left+1,right),arr[right]+end(arr,left,right-1));
}
private static int end(int[] arr, int left, int right){
if (left==right)return 0;
return Math.min(front(arr,left+1,right),+front(arr,left,right-1));
}
}
岛数量问题
class PB {
private static int[][] arr;
private static int N;
private static int M;
public static int process(int[][] arr){
PB.arr=arr;
PB.N=arr.length;
PB.M=arr[0].length;
int res=0;
for (int i=0;i<N;i++){
for (int j=0;j<M;j++){
if (arr[i][j]==1){
res++;
infect(i,j);
}
}
}
return res;
}
private static void infect(int i, int j) {
if (i<0||i>=N||j<0||j>=M||arr[i][j]!=1)return;
arr[i][j]=2;
infect(i-1,j);
infect(i+1,j);
infect(i,j-1);
infect(i,j+1);
}
}
返回字符串的所有子字符串(树形)
- 将该问题看成二分类问题,将所有的单个字符元素是否存在看成一个事件,通过对所有的单个字符判读存在情况就可以得出所有子字符串
- 这样可以理解为二叉树的情况,每一层的每个节点下有两个子节点,表示该层对应的字符是否添加进路径中,最后树的所有叶子节点对应的字符串就是所以子字符串
- 我们采用动态生成树的递归方法对树进行动态的遍历。(该树必定为满树)
class PB {
public static List<String> list=new ArrayList<>();
private static String s;
public static void childrenString(String string){
s=string;
childrenString("",0);
}
private static void childrenString(String chlidString,int i){
if (i==s.length()){
list.add(chlidString);
return;
}
childrenString(chlidString+s.charAt(i),i+1);
childrenString(chlidString,i+1);
}
}
数字转化成字母(树形)
class PB {
public static int process(String s,int i){
if (s.length()==i||(s.length()==i+1&&s.charAt(i)!='0'))return 1;
if (s.charAt(i)=='0')return 0;
int res=process(s,i+1);
if (Integer.parseInt(s.substring(i,i+2))<=26)
res+=process(s,i+2);
return res;
}
}
背包问题(树形)
- 和返回字符串的所有子字符串相似,判断每个物品是否装进了袋子两种选择
- 只需要用递归像树一样遍历所有选择取出最大值即可
- 这样的题可以使用动态规划O(N2),递归O(2^N),关于递归转为动态规划,后续再说。
class PB {
private static int maxBag;
private static int[] weights;
private static int[] values;
public static int process(int[] weights,int[] values,int maxBag){
PB.maxBag=maxBag;
PB.weights=weights;
PB.values=values;
return process(0,0,0);
}
private static int process(int w,int v,int i){
if (w>maxBag)return 0;
if (i==weights.length)return v;
return Math.max(process(w+weights[i],v+values[i],i+1),
process(w,v,i+1));
}
}
贪心算法
最多场会议问题
class Progrem {
Time[] times;
public Progrem(Time[] times, int timePoint){
this.times=times;
arrange(timePoint);
}
private void arrange(int timePoint) {
Arrays.sort(times, Comparator.comparingInt(o -> o.end));
int res=0;
for (Time time : times) {
if (time.start >= timePoint) {
res++;
timePoint = time.end;
}
}
System.out.println(res);
}
static class Time{
int start;
int end;
public Time(int start, int end) {
this.start = start;
this.end = end;
}
}
}
投资收益问题
- 两个优先队列
- 一个按count的小根堆P1,另一个按profit的大根堆P2
- 在P1中找能投资的放在P2中,投资P2堆顶元素
- 循环遍历
class Program {
public static int res(int[] counts,int[] profits,int k,int m){
PriorityQueue<Node> minCount = new PriorityQueue<>(Comparator.comparingInt(o -> o.count));
PriorityQueue<Node> maxProfit = new PriorityQueue<>((o1, o2) -> Integer.compare(o2.profit,o1.profit));
for (int i=0;i<counts.length;i++)
minCount.add(new Node(counts[i],profits[i]));
for (int i = 0; i < k; i++) {
while (!minCount.isEmpty()&&minCount.peek().count<m)
maxProfit.add(minCount.poll());
if (maxProfit.isEmpty()) return m;
m+=maxProfit.poll().profit;
}
return m;
}
private static class Node{
int count;
int profit;
private Node(int count,int profit){
this.count=count;
this.profit=profit;
}
}
}
|