第一节课
前置知识
与运算
两个二进制位都为1时,结果才为1
int a = 5; //0000 0101int b = 6; //0000 0110int c = a & b;System.out.println(c); //0000 0100 = 4
或运算
两个二进制位有一个为1,结果就为1
int a = 5; //0000 0101int b = 6; //0000 0110int c = a | b;System.out.println(c); //0000 0111 = 7
异或运算
两个二进制位不相同,结果为1
int a = 5; //0000 0101int b = 6; //0000 0110int c = a ^ b;System.out.println(c); //0000 0011 = 3
取反运算
0为1,1为0
int a = 5; //0000 0101int b = ~a; //1111 1010//正数取反后,变为了负数,负数的10进制表示形式为 取反+1// 1111 1010// 0000 0101// 0000 0110System.out.println(b); //0000 0110 = -6
左移
m << n //把m向左移动n位0000 1110 << 2 = 0011 1000
有符号右移
有符号右移
m >> n //把m向右移动n位,并在最左边补上n个符号位0000 1110 >> 2 = 0000 0010
无符号右移
m >> n //把m向右移动n位,并在最左边补上n个00000 1110 >> 2 = 0000 0010
打印整数的二进制
public class PrintBinaryTest {public static void print(int temp) {for (int i = 31; i > 0; i--) {//把1左移i位System.out.print((temp & (1 << i)) == 0 ? "0" : "1");}}public static void main(String[] args) {int a = 2;print(a);}}
选择排序
package class01;public class Code04_SelectionSortTest {public static void print(int[] arr) {for (int i : arr) {System.out.print(i);}System.out.println();}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}public static void selectSort(int[] arr) {if (arr == null || arr.length < 2) {return;}int n = arr.length;for (int i = 0; i < n-1; i++) {int minIndex = i;for (int j = i + 1; j < n; j++) {if(arr[j] < arr[minIndex]) {minIndex = j;}}swap(arr, i, minIndex);}}public static void main(String[] args) {int[] arr = {3, 2, 1, 4, 8, 5};print(arr);selectSort(arr);print(arr);}}
冒泡排序
package class01;public class Code05_BubbleSortTest {public static void print(int[] arr) {for (int i : arr) {System.out.print(i);}System.out.println();}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}public static void sort(int[] arr) {if (arr == null || arr.length < 2) {return;}int n = arr.length;for (int end = n - 1; end > 0; end--) {for (int i = 0; i < end; i++) {if (arr[i] > arr[i + 1]) {swap(arr, i, i + 1);}}}}public static void main(String[] args) {int[] arr = {1, 5, 3, 9, 6, 2};print(arr);sort(arr);print(arr);}}
插入排序
package class01;public class Code06_InsertionSortTest {public static void sort(int[] arr) {int n = arr.length;for (int i = 1; i < n; i++) {for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {swap(arr, j, j + 1);}}}public static void swap(int[] arr, int i, int j) {int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}public static void print(int[] arr) {for (int i : arr) {System.out.print(i);}System.out.println();}public static void main(String[] args) {int[] arr = {5, 3, 9, 2, 1, 8};print(arr);sort(arr);print(arr);}}
第二节课
前缀和数组
可以计算出一个数组L到R之间的和
package class02;public class Code01_PreSumTest {public static void preSum(int[] arr, int[] result) {int n = arr.length;result[0] = arr[0];for (int i = 1; i < n; i++) {result[i] = arr[i] + result[i - 1];}}public static void print(int[] arr) {for (int i : arr) {System.out.print(i + " ");}System.out.println();}public static int cal(int[] result, int L, int R) {return L == 0 ? result[R]: result[R] - result[L-1];}public static void main(String[] args) {int[] arr = {1, 4, 7, 4};int[] result = new int[arr.length];preSum(arr,result);print(result);System.out.println(cal(result,0,2));}}
有一个1-5等概率返回的函数,求1-7等概率?
package class02;
public class Code02_RandToRandTest {
//求1-5等概率返回
public static int f1() {
//Math.random() = [0,1)
return (int) ((Math.random() * 5) + 1);
}
//做一个0-1的等概率发生器
// 当返回1,2的时候 = 0
// 当返回4,5的时候 = 1
// 当返回3的时候 重做
public static int f2() {
int ans = 0;
do {
ans = f1();
} while (f1() == 3);
return ans == 0 ? 0 : 1;
}
//0-6等概率返回
public static int f3() {
int ans = 0;
do {
ans = (f2() << 2) + (f2() << 1) + (f2() << 0);
} while (f2() == 7);
return ans;
}
//求1-7等概率返回
//三个二进制位可以表示7种组合
public static int g1() {
return f3() + 1;
}
}
第三节课
有序数组中找到num
public static int find(int[] arr, int n) {
if (null == arr || arr.length < 1) {
return -1;
}
int N = arr.length;
int left = 0;
int right = N - 1;
while (left <= right) {
int mid = (right + left) / 2;
if (arr[mid] == n) {
return mid;
}
if (arr[mid] > n) {
right = mid - 1;
}
if (arr[mid] < n) {
left = mid + 1;
}
}
return -1;
}
有序数组中找到大于等于num最左的位置
public static int mostLeftNoLessNumIndex(int[] arr, int num) {
if (arr == null || arr.length == 0) {
return -1;
}
int L = 0;
int R = arr.length - 1;
int ans = -1;
while (L <= R) {
int mid = (L + R) / 2;
if (arr[mid] >= num) {
ans = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return ans;
}
无序且相邻不相等的数组中找一个局部最小
// arr 整体无序
// arr 相邻的数不相等!
public static int oneMinIndex(int[] arr) {
if (arr == null || arr.length == 0) {
return -1;
}
int N = arr.length;
if (N == 1) {
return 0;
}
if (arr[0] < arr[1]) {
return 0;
}
if (arr[N - 1] < arr[N - 2]) {
return N - 1;
}
int L = 0;
int R = N - 1;
// L...R 肯定有局部最小
while (L < R - 1) {
int mid = (L + R) / 2;
if (arr[mid] < arr[mid - 1] && arr[mid] < arr[mid + 1]) {
return mid;
} else {
if (arr[mid] > arr[mid - 1]) {
R = mid - 1;
} else {
L = mid + 1;
}
}
}
return arr[L] < arr[R] ? L : R;
}
第四节课
反转单链表
public static void print(Node node) {
while (node != null) {
System.out.println(node.num);
node = node.next;
}
}
public static Node reverseSingleList(Node head) {
Node next = null;
Node pre = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
public static void main(String[] args) {
Node node = new Node(1);
node.next = new Node(2);
node.next.next = new Node(3);
print(node);
Node reverseNode = reverseSingleList(node);
System.out.println("-----");
print(reverseNode);
}
反转双向链表






public static DoubleNode reverseDoubleList(DoubleNode head) {
DoubleNode pre = null;
DoubleNode next = null;
while (head != null) {
next = head.next;
head.next = pre;
head.last = next;
pre = head;
head = next;
}
return pre;
}
单链表实现队列
public void offer(V value) {
Node<V> cur = new Node<V>(value);
if (tail == null) {
head = cur;
tail = cur;
} else {
tail.next = cur;
tail = cur;
}
size++;
}
public V poll() {
V ans = null;
if (head != null) {
ans = head.value;
head = head.next;
size--;
}
if (head == null) {
tail = null;
}
return ans;
}
单链表实现栈
public void push(V value) {
Node<V> cur = new Node<>(value);
if (head == null) {
head = cur;
} else {
cur.next = head;
head = cur;
}
size++;
}
public V pop() {
V ans = null;
if (head != null) {
ans = head.value;
head = head.next;
size--;
}
return ans;
}
K个节点的组内逆序调整
给定一个单链表的头节点head,和一个正数K 实现K个节点的小组内部逆序,如果最后一组不够k个就不调整 举例: 调整前:
1->2->3->4->5->6->7->8, k=3调整后:3->2->1->6->5->4->7->8
图解第一组转换







public static class ListNode {
public int val;
public ListNode next;
}
public static ListNode getKGroupEnd(ListNode start, int k) {
while (--k != 0 && start != null) {
start = start.next;
}
return start;
}
public static void reverse(ListNode start, ListNode end) {
end = end.next;
ListNode pre = null;
ListNode cur = start;
ListNode next = null;
while (cur != end) {
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
start.next = end;
}
public static ListNode reverseKGroup(ListNode head, int k) {
ListNode start = head;
ListNode end = getKGroupEnd(start, k);
if(null == end) {
return head;
}
// 第一组凑齐了!
head = end;
reverse(start, end);
// 上一组的结尾节点
ListNode lastEnd = start;
while (lastEnd.next != null) {
start = lastEnd.next;
end = getKGroupEnd(start, k);
if (end == null) {
return head;
}
reverse(start, end);
lastEnd.next = end;
lastEnd = start;
}
return head;
}
两个链表相加
给定两个链表的头节点head1和head2,认为从左到右是某个数字从低位到高位,返回相加之后的链表 举例:
4->3->62->5->3返回:6->8->9解释:634 + 352 = 986 反着看数字
public static class ListNode {
public int val;
public ListNode next;
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
public static ListNode addTwoNumbers(ListNode head1, ListNode head2) {
int len1 = listLength(head1);
int len2 = listLength(head2);
ListNode l = len1 >= len2 ? head1 : head2;
ListNode s = l == head1 ? head2 : head1;
ListNode curL = l;
ListNode curS = s;
ListNode last = curL;
int carry = 0;
int curNum = 0;
while (curS != null) {
curNum = curL.val + curS.val + carry;
curL.val = (curNum % 10);
carry = curNum / 10;
last = curL;
curL = curL.next;
curS = curS.next;
}
while (curL != null) {
curNum = curL.val + carry;
curL.val = (curNum % 10);
carry = curNum / 10;
last = curL;
curL = curL.next;
}
if (carry != 0) {
last.next = new ListNode(1);
}
return l;
}
// 求链表长度
public static int listLength(ListNode head) {
int len = 0;
while (head != null) {
len++;
head = head.next;
}
return len;
}
第五节课
位运算
public static class BitMap {
private long[] bit;
BitMap(int i) {
//(i+64) >> 6 相当于 (i+64) / 64
bit = new long[(i+64) >> 6];
}
public void add(int num) {
//num >> 6 等价于 num / 64
//num % 64 等价于 num & 63
bit[num >> 6] |= (1L << (num & 63));
}
public void delete(int num) {
bit[num >> 6] &= ~(1L << (num & 63));
}
public boolean contains(int num) {
return (bit[num >> 6] & (1L << (num & 63))) != 0;
}
}
加法运算
public static int add(int a, int b) {
int sum = a;
while (b != 0) {
sum = a ^ b;
b = (a & b) << 1;
a = sum;
}
return sum;
}
减法
public static int negNum(int n) {
return add(~n, 1);
}
public static int minus(int a, int b) {
return add(a, negNum(b));
}
乘法
public static int multi(int a, int b) {
int res = 0;
while (b != 0) {
if ((b & 1) != 0) {
res = add(res, a);
}
a <<= 1;
b >>>= 1;
}
return res;
}
除法
public static boolean isNeg(int n) {
return n < 0;
}
public static int div(int a, int b) {
int x = isNeg(a) ? negNum(a) : a;
int y = isNeg(b) ? negNum(b) : b;
int res = 0;
for (int i = 30; i >= 0; i = minus(i, 1)) {
if ((x >> i) >= y) {
res |= (1 << i);
x = minus(x, y << i);
}
}
return isNeg(a) ^ isNeg(b) ? negNum(res) : res;
}
public static int divide(int a, int b) {
if (a == Integer.MIN_VALUE && b == Integer.MIN_VALUE) {
return 1;
} else if (b == Integer.MIN_VALUE) {
return 0;
} else if (a == Integer.MIN_VALUE) {
if (b == negNum(1)) {
return Integer.MAX_VALUE;
} else {
int c = div(add(a, 1), b);
return add(c, div(minus(a, multi(c, b)), b));
}
} else {
return div(a, b);
}
}
