Algorithm 旋转数组(左旋/右旋/二分查找/旋转链表)
一、数组向右旋转
法1.递归 旋转k= 移动一个元素 + 旋转k-1
法2.复制后面k个元素,向后移动然后拷贝回来
法3.reverse前length-k个元素,revese后k个元素,reverse整个数组
/** * Rotate an array of n elements to the right by k steps. * For example, with n = 7 and k = 3, * the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4]. * Note:Try to come up as many solutions as you can, * there are at least 3 different ways to solve this problem. * I.第一种解法直接移动数组 把后面三个数往前移 * II.第二种解法 递归法 f(n) = f(n-1) + 前移一个数字 * III.第三种解法 reverse(nums, nums + n); reverse(nums, nums + k); reverse(nums + k, nums + n); */ public static void rotate_right_1(int[] arr , int k){ //时间复杂度O(n^2) 空间复杂度O(1) //Time Limit Exceeded 运行超时 k %= arr.length; if( k == 0) return ; int temp = arr[arr.length-1]; for(int i=arr.length-1;i>=1;i--) arr[i] = arr[i-1]; arr[0] = temp; rotate_right_1(arr,k-1); } public static void rotate_right_2(int[] arr, int k) { //时间复杂度O(n) 空间复杂度O(n) k %= arr.length; int a[] = new int[k]; for(int i=0;i<k;i++) a[i] = arr[arr.length-k+i]; for(int i=arr.length-k-1;i>=0;i--) arr[i+k] = arr[i]; for(int i=0;i<k;i++) arr[i] = a[i]; } public static void rotate_right_3(int [] arr, int k){ k %= arr.length; reverse(arr,0,arr.length-1-k); reverse(arr,arr.length-k,arr.length-1); reverse(arr,0,arr.length-1); } private static void reverse(int[] arr, int low, int high) { while(high > low) swap(arr,low++,high--); } private static void swap(int[] arr, int low, int high) { int tmp = arr[low]; arr[low] = arr[high]; arr[high] = tmp; }
二、数组向左旋转
向左旋转与向右旋转类似,此处给出一种代码实现:
/** * rotate right是将后面的东西往前面放,rotate left是将前面的东西往后面放 * @param arr * @param k */ public static void rotate_left(int [] arr,int k){ k %= arr.length; reverse(arr,0,k-1); reverse(arr,k,arr.length-1); reverse(arr,0,arr.length-1); }
三、有序数组旋转的二分查找
除了要比较arr[mid]和element的元素外
还要比较arr[mid]和arr[low] arr[high]的递增规律和递减规律
还要比较element和arr[low]arr[high]的大小规律
public static int binarySearch(int arr[], int low ,int high,int element){ if(low > high) return -1; if(low == high){ if(arr[low] != element) return -1; return low; } int mid = (low+high)>>1; if(arr[mid] == element) return mid; else if(arr[mid] > element ){ if(arr[low] <= element || arr[low] > arr[mid]) return binarySearch(arr,low,mid-1,element); else return binarySearch(arr,mid+1,high,element); }else{ if(arr[high] >= element || arr[high] < arr[mid]) return binarySearch(arr,mid+1,high,element); else return binarySearch(arr,low,mid-1,element); } }
四、链表旋转
链表旋转与数组旋转类似,不过链表旋转有三个过程,第一是链表拆分,第二链表逆序,第三链表重组,第三链表再逆序
public static Node rotate_right_linklist(Node head,int k){ int length = getLength(head); k %= length; if(length == 0 || k == 0) return head; Node newhead = head;//从后面往前面数的第K个节点 Node kthNode = head; for(int i=0;i<k-1;i++)//先往前走K-1步 newhead = newhead.next; while(newhead.next != null){//找到从后面往前面数的第K个节点 kthNode = kthNode.next; newhead = newhead.next; } Node tmp = kthNode.next; kthNode.next = null; kthNode = tmp;//断开两个链表 head = reverse(head); kthNode = reverse(kthNode); newhead = head; while(newhead.next != null) newhead = newhead.next; newhead.next = kthNode;//将两个旋转后的linklist拼接上 head = reverse(head); return head; } public static Node reverse(Node head){ Node pre = null; while(head != null){ Node tmp = head.next; head.next = pre; pre = head; head = tmp; } return pre; } private static int getLength(Node head) { Node n = head; int size = 0; while(n != null){ size ++; n = n.next; } return size; } class Node{ public int value; public Node next; public Node(int data){ this.value = data; } }

浙公网安备 33010602011771号