Java 算法题笔记(十一)

和为s 的两个数

输入一个递增排序的数组和一个数字s,在数组中查找两个数,得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。

举例说明

例如输入数组{1 、2 、4、7 、11 、15 }和数字15. 由于4+ 11 = 15 ,因此输出4 和11 。

暴力破解当然可以,但是考虑到数组有序为递增的,所以要用一下这个条件,更好。

public static List<Integer> findNumbersWithSum(int[] data, int sum) {
        List<Integer> result = new ArrayList<>(2);

        if (data == null || data.length < 2) {
            return result;
        }

        // 定义左右指针
        int right = data.length - 1;
        int left = 0;
        long curSum; // 统计和,取long是防止结果溢出

        while (left < right) {
            curSum = data[left] + data[right];

            // 相等即命中
            if (curSum == sum) {
                result.add(data[left]);
                result.add(data[right]);
                break;
            } else if (curSum < sum) {
                // 如果< sum ,那就使和大一点,移动左边的指针,使其和变大
                left++;
            } else {
                // 反之,右边的指针往左移,使和变小
                right--;
            }
        }

        return result;
    }

输入一个正数s,打印出所有和为s 的连续正数序列(至少两个数)

例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打出3 个连续序列1~5、4~6 和7~8。

    // 输入一个正数s,打印出所有和为s 的连续正数序列(至少两个数)。
    public static List<List<Integer>> findContinuousSequence(int sum) {
        List<List<Integer>> result = new ArrayList<>();
        if (sum < 3) {
            return result;
        }

        int small = 1;
        int big = 2;
        int middle = (1 + sum) / 2;
        int curSum = small + big;

        // 用middle 来控制外层循环,很巧妙
        // 针对这种类型的题,可以当成公式
        while (small < middle) {
            if (curSum == sum) {
                List<Integer> list = new ArrayList<>(2); // 节省空间,内部有扩容机制
                for (int i = small; i <= big; i++) {
                    list.add(i);
                }
                result.add(list);
            }

            while (curSum > sum && small < middle) {
                // 如果curSum > sum 那么我们就去掉一点看看是否可以
                curSum -= small;
                small++;

                if (curSum == sum) {
                    List<Integer> list = new ArrayList<>(2);
                    for (int i = small; i <= big; i++) {
                        list.add(i);
                    }
                    result.add(list);
                }
            }

            // curSum < sum 那就big++ 来使序列的值扩大
            // small < middle 这个条件使循环结束
            big++;
            curSum += big;
        }

        return result;
    }

左旋转字符串

比如输入字符串”abcdefg”和数字2,该函数将返回左旋转2 位得到的结”cdefgab”。

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。

public static char[] leftRotateString(char[] data, int n) {
        if (data == null || n < 0 || n > data.length) {
            return data;
        }
        
        reverse(data, 0, data.length - 1);
        reverse(data, 0, data.length - n - 1);
        reverse(data, data.length - n, data.length - 1);

        return data;
    }

    public static void reverse(char[] data, int start, int end) {
        if (data == null || data.length < 1 || start < 0 || end > data.length || start > end) {
            return;
        }
        
        // 这样反转,效率提高一半
        // start 与 end 位交换
        while (start < end) {
            char tmp = data[start];
            data[start] = data[end];
            data[end] = tmp;

            start++;
            end--;
        }
    }

高效移动数组

[0,1,0,3,12] ->  [1,3,12,0,0]

  1. 必须在原数组上操作,不能拷贝额外的数组。
  2. 尽量减少操作次数。
public void moveZeroes(int[] nums) {
        int i = 0;
        for(int j = 0; j < nums.length; j++){
            if(nums[j] != 0){
                if (i != j)
                    nums[i] = nums[j];
                i++;
            }
        }
        for(; i < nums.length; i++){
            nums[i] = 0;
        }
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值