1. Swap Nodes in Pairs

Given a linked list, swap every two adjacent nodes and return its head.

For example,

Given 1->2->3->4, you should return the list as 2->1->4->3.

Your algorithm should use only constant space. You may not modify the values in the list, only nodes itself can be changed.

思路:模拟即可,思路不清楚时最好再纸上画画,确定节点指针的改变规则和顺序。交换顺序是这样的,用 cur 指针指向第一个,如果它不为空并且他的next也不为空则可以进行交换。交换时的步骤:(1)用temp暂存cur所指的第一个节点,(2)将cur指向第二个节点,也就是cur.next,(3)将第一个节点的next指向第二个节点的next,(4)第二个节点指向第一个节点,(5)将cur指向第三个节点,(6)这步容易忽略,要将改变后的第二个节点的next指向第四个节点(如果不为空的情况) 。这是因为一开始改变的时候,第一个节点前面没有节点,但是之后每个节点前面都是有节点的,所以之后不光要串连后面,还要串连前面。

public class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode cur = head;
        ListNode newHead = head.next;
        while (cur != null && cur.next != null) {
            ListNode tmp = cur;
            cur = cur.next;
            tmp.next = cur.next;
            cur.next = tmp;
            cur = tmp.next;
      // 第6步
if (cur != null && cur.next != null) tmp.next = cur.next; } return newHead; } }

 

2. Divide Two Integers

Divide two integers without using multiplication, division and mod operator. If it is overflow, return MAX_INT.

思路:可以使用加法来实现除法,但这题要注意的是一些临界情况,比如正负,溢出,除数被为0等情况。试了下结果Time Limit exceeded,而且这里发现了一个很有意思的问题,java中Math.abs(-2147483648)的返回值应该是什么?。那么改进下这个想法,不是一个一个加除数,而是成倍的增加除数。比如对于10/1,原来的算法是 1+1+1+1+1+1+1+1+1+1 总共循环10次,👆是10。现在变成这样1+1+2+4,商也相应的为1+1+2+4,但是现在总数是8,再加上8超过10,所以对其差 10-8=2 作为新的被除数,1为除数继续按上面方法求商。最后将商加再一起即可。 其实就是将 d/c 变为(a+b)/ c =a/c+b/c 其中d=a+b,再加上成倍的增加除数使得循环次数能大大减少。

public int divide(int dividend, int divisor) {
    //Reduce the problem to positive long integer to make it easier.
    //Use long to avoid integer overflow cases.
    int sign = 1;
    if ((dividend > 0 && divisor < 0) || (dividend < 0 && divisor > 0))
        sign = -1;
    long ldividend = Math.abs((long) dividend);
    long ldivisor = Math.abs((long) divisor);
    
    //Take care the edge cases.
    if (ldivisor == 0) return Integer.MAX_VALUE;
    if ((ldividend == 0) || (ldividend < ldivisor))    return 0;
    
    long lans = ldivide(ldividend, ldivisor);
    
    int ans;
    if (lans > Integer.MAX_VALUE){ //Handle overflow.
        ans = (sign == 1)? Integer.MAX_VALUE : Integer.MIN_VALUE;
    } else {
        ans = (int) (sign * lans);
    }
    return ans;
}

private long ldivide(long ldividend, long ldivisor) {
    // Recursion exit condition
    if (ldividend < ldivisor) return 0;
    
    //  Find the largest multiple so that (divisor * multiple <= dividend), 
    //  whereas we are moving with stride 1, 2, 4, 8, 16...2^n for performance reason.
    //  Think this as a binary search.
    long sum = ldivisor;
    long multiple = 1;
    while ((sum+sum) <= ldividend) {
        sum += sum;
        multiple += multiple;
    }
    //Look for additional value for the multiple from the reminder (dividend - sum) recursively.
    return multiple + ldivide(ldividend - sum, ldivisor);
}

 

3. Next Permutation 

Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers. If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).

The replacement must be in-place, do not allocate extra memory.

Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.

1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

思路:这题咋看不知道要干嘛,其实就是对于给定的一个数字排列,给出它下一个按字母序较大的排列,比如 1,2,3 → 1,3,2,如果是降序排列的数字组,比如3,2,1,那么给出的应该是初始排列1,2,3。完整的排列顺序如下:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1 (再下一个就是1 2 3了)

解题思路是先倒序扫描数组,遇到第一个num[i-1]<nums[i],那么从num[i]到nun[n-1]是相反顺序排序,比如 3,2,1这样。为了找到下一个按字母序较大的排列,要做的是使得改变的位置越靠后,并且改变的尽量的少,所以要改变的是索引 i-1 位置上的,拿它和 i 到 n-1 位置上比它大的一个最小值交换即可(即从比它大的所有值中选一个最小的)。

For example, original number is 121543321, we want to swap the ‘1’ at position 2 with ‘2’ at position 7.

完成上述步骤后,还要使剩下的较高位位置部分尽可能小(因为只要低位位置,也就是靠前的数字较大那么字典序上就较大了,后面再怎么排列都没用,因为要找的是下一个排列,所以要是得后面的部分的排列在字典序上尽可能的小),直接逆置排序(也就是升序排序原来的降序序列) num[i,n-1] 即可。

import java.util.*;

public class LeetCode{
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String inp=sc.nextLine();
        int[] num=new int[inp.length()];
        for(int i=0;i<inp.length();i++)
            num[i]=inp.charAt(i)-'0';
        nextPermutation(num);
        for(int a:num)
            System.out.print(a);
    }
    
    public static void nextPermutation(int[] num){
        int n=num.length;
        if(n<2)
            return;
        int index=n-1;
        while(index>0){
            if(num[index-1]<num[index])
                break;
            index--;
        }
        if(index==0){
            reverseSort(num,0,n-1);
            return;
        }else{
            int val=num[index-1];
            int j=n-1;
            while(j>=index){
                if(num[j]>val)
                    break;
                j--;
            }
            swap(num,index-1,j);
            reverseSort(num,index,n-1);
            return;
        }        
    }
    
    public static void swap(int[] num, int i, int j){
        int temp=0;
        temp=num[i];
        num[i]=num[j];
        num[j]=temp;
    }
    
   // 原来从i到n-1是降序的,逆置了后就成了升序
public static void reverseSort(int[] num,int start,int end){ if(start>end) return;
// 注意这里逆排序中索引的对应关系,学到了
for(int i=start;i<=(end+start)/2;i++) swap(num,i,start+end-i); } }
posted on 2018-01-19 17:44  f91og  阅读(162)  评论(0编辑  收藏  举报