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;
    }
}

 

posted @ 2015-10-05 16:38  √珞珈搬砖工√  阅读(461)  评论(0)    收藏  举报