1. 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
1) 暴力解法,两层循环嵌套遍历,时间复杂度为O(N²),空间复杂度为O(1)
public static int[] twoSum(int[] nums,int target) {
for (int i=0;i<nums.length;i++) {
for (int j= i+1;j< nums.length;j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i,j};
}
}
}
return new int[0];
}
2) 利用哈希表,数组值为key,对应的数组下标为value,时间复杂度为O(N),空间复杂度为O(N)
public static int[] twoSum(int[] nums,int target) {
Map<Integer,Integer> hashTable = new HashMap<Integer,Integer>();
for (int i=0;i<nums.length;i++) {
int firstValue = target - nums[i];
if (hashTable.containsKey(firstValue)) {
return new int[]{hashTable.get(firstValue),i};
}
hashTable.put(nums[i],i);
}
return new int[0];
}
2,一个数组中只有一种数出现了奇数次,其他都出现了偶数次,怎么找到并打印这种数
此题目考察的是异或运算(^)满足交换律和结合律
异或运算(^):相同为0,不同为1
public static void printOddNumOne(int[] arr) {
int result = 0;
for (int i=0;i<arr.length;i++) {
result ^= arr[i];
}
System.out.print(result);
}
3,一个数组中只有两种数出现了奇数次,其他都出现了偶数次,怎么找到并打印这两种数
此题目考察的知识点是位运算
异或运算(^):相同为0,不同为1
0&0=0; 0&1=1; 1&0=1; 1&1=0;
与运算(&):两位同时为1,则值为1。否则为0
0&0=0; 0&1=1; 1&0=1; 1&1=1;
首先如何提取出一个数N的二进制位的最右边的1?
anwser = N & (~N + 1)
eg.
N == 0101 0110
~N == 1010 1001
(~N+1) == 1010 1010
N&(~N+1)== 0000 0010 (注意:+1只是在最末位+1操作,最多只是最后两位发生变化)
public static void printOddNum2(int[] arr) {
int eor = 0;
for (int i=0;i<arr.length;i++) {
eor ^= arr[i];
}
//结果是 eor = a ^ b 且 eor ≠ 0,因此eor必然有一个位置上是1
int rightOne = eor & (~eor + 1); //提取eor上最右侧的1,也就是说其余位均为0
int onlyOne = 0;
for (int i=0;i<arr.length;i++) {
if ((arr[i] & rightOne) != 0) {
onlyOne ^= arr[i];
}
}
// onlyOne = a 或者 b,所以onlyOne ^ eor = onlyOne ^ a ^ b = b 或者 a
System.out.print("one:" + onlyOne);
System.out.print("another:" + (onlyOne ^ eor));
}
4,删除一个单链表中指定值的节点
public static Node removeValueNode(Node head,int num) {
//如果head节点是指定值的节点,就往后移
while (head != null) {
if (head.value != num) {
break;
}
head = head.next;
}
// head来到第一个不需要删除的位置
Node pre = head;
Node cur = head;
while (cur != null) {
if (cur.value == num) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return head; //注意返回的还是head 而不是pre或cur
}
5,反转单链表和双向链表
//单链表
public static class Node {
public int value;
public Node next;
public Node(int data) {
value = data;
}
}
//双向链表
public static class DoubleNode {
public int value;
public DoubleNode last;
public DoubleNode next;
public DoubleNode(int data) {
value = data;
}
}
//反转单链表
public static Node reverseLinkedList(Node head) {
Node pre = null;
Node next = null;
while (head != null) {
next = head.next;
head.next = pre;
pre = head;
head = next;
}
return pre;
}
//反转双向链表
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;
}
6,如何用数组实现不超过固定大小的队列和栈
栈:正常使用
队列:环形数组
public static class MyQueue {
private int[] arr;
private int pushi;
private int pulli;
private int size;
private final int limit;
public MyQueue(int limit){
arr = new int[limit];
pushi = 0;
pulli = 0;
size = 0;
this.limit = limit;
}
public void push(int value) {
if (size == limit) {
throw new RuntimeException("队列满了,不能再加了");
}
size++;
arr[pushi] = value;
pushi = nextIndex(pushi);
}
public int pop() {
if (size == 0) {
throw new RuntimeException("队列空了,不能再拿了");
}
size--;
int ans = arr[pulli];
pulli = nextIndex(pulli);
return ans;
}
private int nextIndex(int index) {
return index < limit - 1 ? index + 1 : 0;
}
}
7,如何用栈来实现队列
需要申请两个栈 eg
public static class TwoStacksImplementQueue {
public Stack<Integer> s1;
public Stack<Integer> s2;
public TwoStacksImplementQueue() {
s1 = new Stack<Integer>();
s2 = new Stack<Integer>();
}
//s1栈向s2栈中倒入数据
private void s1ToS2() {
if (s2.empty()) {
while (!s1.empty()) {
s2.push(s1.pop());
}
}
}
//入队
public void add(int pushInt) {
s1.push(pushInt);
s1ToS2();
}
//出队
public int poll() {
if (s1.empty() && s2.empty()) {
throw new RuntimeException("Queue is empty");
}
s1ToS2();
return s2.pop();
}
public int peek() {
if (s1.empty() && s2.empty()) {
throw new RuntimeException("Queue is empty");
}
s1ToS2();
return s2.peek();
}
}
8,用递归方法求数组中的最大值
public static int getMax(int[] arr) {
return process(arr,0,arr.length-1);
}
public static int process(int[] arr,int L, int R) {
//base case基准条件,在递归中一定要存在
if (L == R) {
return arr[L];
}
int mid = L + ((R - L) >> 1);
int leftMax = process(arr,L,mid);
int rightMax = process(arr,mid+1,R);
return Math.max(leftMax,rightMax);
}
思考:递归函数在系统里是怎么实现的?系统栈
9,归并排序
public static void process(int[] arr,int L, int R) {
//base case基准条件,在递归中一定要存在
if (L == R) {
return;
}
int mid = L + ((R - L) >> 1);
process(arr,L,mid);
process(arr,mid+1,R);
merge(arr,L,mid,R);
}
public static void merge(int[] arr, int L,int M,int R) {
int[] help = new int[R-L+1];
int i=0;
int p1 = L;
int p2 = M + 1;
while (p1<=M && p2 <= R) {
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
for (i=0;i<help.length;i++) {
arr[L+i] = help[i];
}
}
10,arr[L...R] 荷兰国旗问题的划分,以arr[R]做划分值
public static void netherlandsFlag(int[] arr,int L,int R) {
if (L >= R) {
return;
}
int leftFlag = L -1;
int rightFlag = R;
int index = L;
while (index < rightFlag) {
if (arr[index] < arr[R]) {
++leftFlag;
swap(arr,index,leftFlag);
index++;
} else if (arr[index] == arr[R]) {
index++;
} else {
--rightFlag;
swap(arr,index,rightFlag);
}
}
swap(arr,rightFlag,R);
}
11,快速排序3.0
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process(arr,0,arr.length-1);
}
public static void process(int[] arr,int L,int R) {
if (L >= R) {
return;
}
//随机选取一个数作为划分值,并放在了最右边
swap(arr,L+(int)(Math.random() * (R-L + 1)),R);
int[] equalArea = partition(arr,L,R);
process(arr,L,equalArea[0]-1);
process(arr,equalArea[1]+1,R);
}
//arr[L...R] 荷兰国旗问题的划分,以arr[R]做划分值,返回相等区域的起始位置下标组成的数组
public static int[] partition(int[] arr,int L,int R) {
if (L > R) {
return new int[]{-1,-1};
}
if (L == R) {
return new int[]{L,R};
}
int leftFlag = L -1;
int rightFlag = R;
int index = L;
while (index < rightFlag) {
if (arr[index] < arr[R]) {
++leftFlag;
swap(arr,index,leftFlag);
index++;
} else if (arr[index] == arr[R]) {
index++;
} else {
--rightFlag;
swap(arr,index,rightFlag);
}
}
swap(arr,rightFlag,R);
return new int[]{leftFlag+1,rightFlag};
}