剑指offerJAVA版笔记(第五天、第二十五题至第三十题)

25.复杂链表的复制

  • 题目描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
  • 解题思路:
  • 1.遍历链表,复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
  • 2.重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
  • 3.拆分链表,将链表拆分为原链表和复制后的链表
public class Clone {
    public RandomListNode Clone(RandomListNode pHead) {
        if(pHead == null) {
            return null;
        }

        RandomListNode currentNode = pHead;
        //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
        while(currentNode != null){
            RandomListNode cloneNode = new RandomListNode(currentNode.label);
            RandomListNode nextNode = currentNode.next;
            currentNode.next = cloneNode;
            cloneNode.next = nextNode;
            currentNode = nextNode;
        }

        currentNode = pHead;
        //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
        while(currentNode != null) {
            currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
            currentNode = currentNode.next.next;
        }

        //3、拆分链表,将链表拆分为原链表和复制后的链表
        currentNode = pHead;
        RandomListNode pCloneHead = pHead.next;
        while(currentNode != null) {
            RandomListNode cloneNode = currentNode.next;
            currentNode.next = cloneNode.next;
            cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
            currentNode = currentNode.next;
        }

        return pCloneHead;
    }
}

26.二叉搜索树与双向链表

  • 题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
public class Convert {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null){
            return null;
        }
        TreeNode list = null;
        Stack<TreeNode> stack = new Stack<>();
        while (pRootOfTree != null || !stack.isEmpty()){
            if (pRootOfTree != null){
                stack.push(pRootOfTree);
                pRootOfTree = pRootOfTree.right;
            }else{
                pRootOfTree = stack.pop();
                if (list == null){
                    list = pRootOfTree;
                }else{
                    list.left = pRootOfTree;
                    pRootOfTree.right = list;
                    list = pRootOfTree;
                }
                pRootOfTree = pRootOfTree.left;
            }
        }
        return list;
    }
}

27.字符串的排列

  • 题目描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
  • 输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
  • 解题思路:
    • 解析:http://www.cnblogs.com/cxjchen/p/3932949.html (感谢该文作者!)
    • 对于无重复值的情况
    • 固定第一个字符,递归取得首位后面的各种字符串组合;
    • 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。
    • 假如有重复值呢?
    • *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。
    • 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。
    • 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。
    • 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。
    • 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数,
    • 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
public ArrayList<String> Permutation(String str){

        ArrayList<String> list = new ArrayList<String>();
        if(str!=null && str.length()>0){
            PermutationHelper(str.toCharArray(),0,list);
            Collections.sort(list);
        }
        return list;
    }
    private void PermutationHelper(char[] chars,int i,ArrayList<String> list){
        if(i == chars.length-1){
            list.add(String.valueOf(chars));
        }else{
            Set<Character> charSet = new HashSet<Character>();
            for(int j=i;j<chars.length;++j){
                if(j==i || !charSet.contains(chars[j])){
                    charSet.add(chars[j]);
                    swap(chars,i,j);
                    PermutationHelper(chars,i+1,list);
                    swap(chars,j,i);
                }
            }
        }
    }

    private void swap(char[] cs,int i,int j){
        char temp = cs[i];
        cs[i] = cs[j];
        cs[j] = temp;
    }

28.数组中出现次数超过一半的数字

  • 题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
  • 解题思路:用Map存储每个数字出现的次数。
public int MoreThanHalfNum_Solution(int [] array) {
        Map<Integer,Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < array.length ; i++) {
            if(!map.containsKey(array[i])){
                map.put(array[i],1);
            }else {
                map.put(array[i],(map.get(array[i])+1));
            }
        }
        for (int i = 0 ; i <(array.length / 2 + 1) ;i ++){
            if (map.get(array[i]) > (array.length / 2)){
                return array[i];
            }
        }
        return 0;
    }

29.最小的K个数

  • 题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
  • 解题思路:排序,返回序列。
 public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> result = new ArrayList<>();
        if (k > input.length){
            return result;
        }
        for (int i = 0; i < input.length - 1 ; i++) {
            for (int j = i + 1; j < input.length ; j++) {
                if (input[i] > input[j]){
                    int num = input[i];
                    input[i] = input[j];
                    input[j] = num;
                }
            }

        }

        for (int i = 0; i < k ; i++) {
            result.add(input[i]);
        }
        return result;
    }

30.连续子数组的最大和

  • 题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
  • 解题思路:双重for循环遍历数组求和即可。
    public int FindGreatestSumOfSubArray(int[] array) {
        int max = -999999;
        for (int i = 0; i < array.length - 1 ; i++) {
            int sum = 0;
            for (int j = i; j < array.length;j++){
                sum = sum + array[j];
                if(sum > max){
                    max = sum;
                }
            }
        }
        return max;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值