1. 基础知识
1.1 输入数组以引用的方式作为方法的参数
2.算法基础技巧
2.1 双指针算法(原地算法)技巧
双指针又称为快慢指针
使用双指针可以使不用新建一个数组,从而使这道题的时间复杂度从O(n)降低到O(1)
class Solution {
public void moveZeroes(int[] nums) {
if(nums == null || nums.length == 0){
return;
}
int i = 0 ;
int j = 0 ;
for(;i < nums.length ; i++){
if(nums[i] != 0){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
j++;
}
}
}
}
优化写法:不交换两个元素,直接赋值
class Solution {
public void moveZeroes(int[] nums) {
if(nums == null || nums.length == 0){
return;
}
int i = 0 ;
int j = 0 ;
for(;i < nums.length ; i++){
if(nums[i] != 0){
if(i != j){
nums[j] = nums[i];
}
j++;
}
}
for(; j < nums.length; j++){
nums[j] = 0;
}
}
}
2.2 双指针编程技巧(对撞指针)
class Solution {
public void reverseString(char[] s) {
int head = 0;
int tail = s.length - 1;
while(head != tail && tail > head){
char temp = s[head];
s[head] = s[tail];
s[tail] = temp;
head++;
tail--;
}
}
}
class Solution {
public boolean isPalindrome(String s) {
StringBuffer sgood = new StringBuffer();
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (Character.isLetterOrDigit(ch)) {
sgood.append(Character.toLowerCase(ch));
}
}
int n = sgood.length();
int left = 0, right = n - 1;
while (left < right) {
if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))) {
return false;
}
++left;
--right;
}
return true;
}
}
2.3 递归
方法自身不能无限制的调用自身,否则会出现栈溢出的情况。需要有一个限制条件来退出递归
递归的特点
1、大问题可以拆分为小问题,将小问题解决了,大问题也就解决了
2、每一个子问题的解决的方法逻辑是一样的
3、一定要有递归终止条件
写递归代码分两步
- 写出递推公式 f(n) = f(n -1) + f(n-2);
- 写出递归终止条件:f(1) = 1 ; f(2) = 2;
不用纠结与细节,写出上面的两步,递归代码基本也就写完了
爬楼梯问题:
class Solution {
public int fib(int n) {
if(n < 2){
return n;
}
int leftFib = fib(n - 1);
int rightFib = fib(n - 2);
return leftFib + rightFib;
}
}
2 排序算法
2.1 排序算法基础知识
升序排序(默认)
降序排序
- 排序算法的稳定性
- 何为原地排序算法
2.2 冒泡排序
冒泡排序代码实现
public static void main(String[] args) {
int[] arr = new int[]{4,2,5,1,6,9};
for(int i = 1 ; i <= arr.length; i++){ // 控制冒泡轮数
int time = arr.length - i;
for(int j = 0 ; j < time ;j++){ // 控制每轮比较次数
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for(int i = 0 ; i < arr.length ; i++){
System.out.println(arr[i]);
}
}
2.3 选择排序
选择排序是将数组中最小的元素找到,并放到数组的第一个位置,
接下来在找剩下元素最小的元素,放到第二个位置
代码实现
public static void selectSort(int[] arr){
if(arr == null || arr.length == 0){
return ;
}
for(int i = 0 ; i < arr.length; i++){
int minIndex = i;
for(int j = i + 1; j < arr.length ;j++){
if(arr[j] < arr[minIndex]){
minIndex = j;
}
}
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
2.4 插入排序
将元素插入到已经有序的数组当中(第一步的时候,我们假设第一个元素是有序的即可)
代码实现
public static void insertSort(int arr[]){
// i 没必要从0开始,因为第一个元素假设他有序
for(int i =1;i < arr.length ; i++){
for(int j = i ; j > 0 ; j--){
if(arr[j] < arr[j-1]){
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
}else{
//如果当前元素比前一个元素还要大
//那就没必要在往前比较了
break;
}
}
}
}
优化后的插入排序
public static void insertSort(int arr[]){
// i 没必要从0开始,因为第一个元素假设他有序
for(int i =1;i < arr.length ; i++){
int temp = arr[i];
int j;
for(j = i ; j > 0 ; j--){
if(j != 0){
if(temp < arr[j-1]){
arr[j] = arr[j-1];
}else{
//如果当前元素比前一个元素还要大
//那就没必要在往前比较了
break;
}
}
}
arr[j] = temp;
}
}
2.5 冒泡、选择、插入排序的比较
性能高到低
插入(用的最多的)> 选择(不是稳定性算法) > 冒泡