Page cover

👍数组与循环

Array and Loop

485 · 生成给定大小的数组(入门)

题目要求

给你一个大小size,生成一个元素从1 到 size的数组。

样例 1:
	输入:  size = 4
	输出: [1, 2, 3, 4]
	
	样例解释: 
	 返回一个顺序填充1到4的数组。

解决方案

使用for循环向数组内添加元素并返回

public class Solution {
    /**
     * @param size: An integer
     * @return: An integer list
     */
    public List<Integer> generate(int size) {
        // write your code here
        List<Integer> array = new ArrayList<>();
        for (int i = 1; i <= size; i++) {
            array.add(i);
        }
        return array;
    }
}

484 · 交换数组两个元素(入门)

题目要求

给你一个数组和两个索引,交换下标为这两个索引的数字。

输入:  [1, 2, 3, 4], index1 = 2, index2 = 3
输出:  交换后你的数组应该是[1, 2, 4, 3], 不需要返回任何值,只要就地对数组进行交换即可。
样例解释: 就地交换,不需要返回值。

解决方案

采用最基础的数组取值Array[index]来取出两个目标值,然后交换。

public class Solution {
    /**
     * @param A: An integer array
     * @param index1: the first index
     * @param index2: the second index
     * @return: nothing
     */
    public void swapIntegers(int[] A, int index1, int index2) {
        // write your code here
        if (A[index1] == A[index2]) {
            return;
        } else {
            int tmp = A[index1];
            A[index1] = A[index2];
            A[index2] = tmp;
        }
    }
}

463 · 整数排序(入门)

题目要求

给一组整数,按照升序排序,使用选择排序,冒泡排序,插入排序或者任何 O(n2) 的排序算法。

样例  1:
	输入:  [3, 2, 1, 4, 5]
	输出:  [1, 2, 3, 4, 5]
	
	样例解释: 
	返回排序后的数组

解决方案

选择排序:两个指针,第一个指基准,第二个找最小,找到最小时交换基准和最小,然后继续寻找

public class Solution {
    /**
     * 使用选择排序
     * @param A: an integer array
     * @return: nothing
     */
    public void sortIntegers(int[] array) {
        // write your code here
        for (int i = 0; i < array.length; i++) {
            int minimum = i;
            for (int j = i; j < array.length; j++) {
                if (array[j] < array[minimum]) {
                    minimum = j;
                }
            }
            swap(array, i, minimum);
        }
    }

    private static void swap(int[] arr, int currentIndex, int minIndex) {
        // 将当前值和最小值交换
        int temp = arr[currentIndex];
        arr[currentIndex] = arr[minIndex];
        arr[minIndex] = temp;
    }
}

214 · 数组的最大值(入门)

题目要求

给一个浮点数数组,求数组中的最大值。

输入:  [1.0, 2.1, -3.3]
输出: 2.1	
样例解释: 返回最大的数字

解决方案

就是普通的找最大值:记录下初始最大值(默认index=0),从index=1开始找,如果有当前值比最大值大,就更新这个最大值。遍历完整个数组之后返回这个最大值。

public class Solution {
    /**
     * @param A: An integer
     * @return: a float number
     */
    public float maxOfArray(float[] A) {
        // write your code here
        int maxIndex = 0; 
        for (int i = 1; i < A.length; i++) {
            if (A[i] > A[maxIndex]) {
                maxIndex = i;
            }
        }
        return A[maxIndex];
    }
}

25 · 打印X(入门)

题目要求

输入一个正整数N, 你需要按样例的方式返回一个字符串列表。

Input: n = 5
Output: ["X   X", " X X ", "  X  ", " X X ", "X   X"]
Refer to:
X   X 
 X X  
  X   
 X X  
X   X 

解决方案

public class Solution {
    public List<String> printX(int n) {     
        ArrayList<String> res=new ArrayList<>();//创建一个存放String类型属性的ArrayList,名称为res
        char[] line=new char[n];//创建一个长度为n的字符型数组line
        for(int i=0;i<n;i++){//外循环遍历正整数n的次数
            for(int j=0;j<n;j++){//该循环为了辅助初始化字符型数组中的每个属性
                line[j]=' ';//初始化字符型数组中的每个属性
            }
            line[i]='X';//左边对应位置赋值X
            line[n-i-1]='X';//右边对应位置赋值X
            res.add(String.valueOf(line));//将得到的line转换成字符串的形式增加到ArrayList
        }
        return res;//返回ArrayList
    }
}

298 · 寻找素数(入门)

题目要求

输出n以内所有的素数。

输入:5
输出:[2, 3, 5]

解决方案

参考网页:

public class Solution {
    /**
     * @param n: an integer
     * @return: return all prime numbers within n.
     */
    public List<Integer> prime(int n) {
        // write your code here
        List<Integer> result = new ArrayList<>();
        boolean isPrime = true;
        // 因为结果要包含n这个数,所以是i<=n
        for (int i = 2; i <= n; i++) {
            for (int j = 2; j < i; j++) {
                if (i % j == 0) {
                    isPrime = false;
                }
            }
            if (isPrime) result.add(i);
            isPrime = true;
        }
        return result;
    }
}

297 · 寻找最大值(入门)

题目要求

寻找 n 个数中的最大值。

输入:[1, 2, 3, 4, 5]
输出:5

解决方案

使用Collections里的max()方法

public class Solution {
    /**
     * @param nums: the list of numbers
     * @return: return the maximum number.
     */
    public int maxNum(List<Integer> nums) {
        // write your code here
        int num = Collections.max(nums);
        return num;
    }
}

1334 · 旋转数组(简单)

题目要求

给定一个数组,将数组向右移动k步,其中k为非负数。

输入: [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转1步: [7,1,2,3,4,5,6]
向右旋转2步: [6,7,1,2,3,4,5]
向右旋转3步: [5,6,7,1,2,3,4]

解决方案 (我自己的)

分类讨论,切片复制,最后组合

注意:旋转的次数是可能大于数组长度的!!需要求出真正有效的旋转次数!!

public class Solution {
    /**
     * @param nums: an array
     * @param k: an integer
     * @return: rotate the array to the right by k steps
     */
    public int[] rotate(int[] nums, int k) {
        // 如果数组只有一个数,不管旋转几次都是它自己,直接返回
        if (nums.length == 1) return nums;
        // 对于数组长度大于一的情况
        // 1. 旋转次数 < 数组长度: 正常处理
        // 2. 旋转次数 > 数组长度:对k和length进行取余数运算,计算出真正旋转的次数(例如,长度为7的数组旋转10次,前7次结束后还是它本身,真正有效果的为后三次 10 % 7 = 3)
        if (k > nums.length) {
            k = k % nums.length;
        }
        // 如果数组只有两个数,当k为1的时候就相当于交换;否则就还是它本身
        if (nums.length == 2 & k == 1) {
            swap(nums, 0, 1);
            return nums;
        } else if (nums.length == 2 & k != 1) {
            return nums;
        }
        // 切片:选择出要被旋转的
        int[] waitForRotate = Arrays.copyOfRange(nums, nums.length-k, nums.length);
        // 切片:选择出不变的(剩下的)那一些
        int[] unchanged =  Arrays.copyOfRange(nums, 0, nums.length-k);
        // 新建一个结果数组,将“被旋转”的复制进来,并且设定该数组长度为原数组的长度
        int[] result = Arrays.copyOf(waitForRotate, nums.length);
        // 将“剩下的”复制进“结果数组”,从“剩下的”index为0的地方开始复制,“结果数组”最后一位开始粘贴,复制的长度为“剩下的”数组的长度
        System.arraycopy(unchanged, 0, result, waitForRotate.length, unchanged.length);
        
        return result;
    }

    private static void swap(int[] arr, int a, int b) {
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}

解决方案(排名第一

public class Solution {
    /**
     * @param nums: an array
     * @param k: an integer
     * @return: rotate the array to the right by k steps
     */
    public int[] rotate(int[] nums, int k) {
        // Write your code here
        int len = nums.length;
        k = k % len;
        int[] ret = new int[len];
        for (int i = 0; i < len; i++) {
            ret[i] = nums[(i + len - k) % len];
        }
        return ret;
    }
}

807 · 回文数 II(简单)

题目要求

判断一个非负整数 n 的二进制表示是否为回文数。

输入: n = 3
输出: True
解释:
3 的二进制表示为:11。

输入: n = 6
输出: False
解释:
6 的二进制表示为:110。

解决方案

public class Solution {
    /**
     * @param n: non-negative integer n.
     * @return: return whether a binary representation of a non-negative integer n is a palindrome.
     */
    public boolean isPalindrome(int n) {
        // Write your code here
        // Step 1: 十进制转换为二进制char类型Array
        String decimal = Integer.toBinaryString(n);
        char[] decimalChar = decimal.toCharArray();
        // Step 2: 设置左起和右起两个指针,默认结果为false
        int left = 0, right = decimalChar.length - 1;
        boolean result = false;
        // Step 3: 开始循环判断,两个指针分别向中间靠拢
        while (left <= right) {
            // 如果有一个匹配不上就直接返回false,或者所有的都能匹配上才返回true
            if (decimalChar[left]==decimalChar[right]) {
                result = true;
            } else {
                return false;
            }
            left += 1;
            right -= 1;
        }

        return result;
    }
}

768 · 杨辉三角(简单)(需要复习)

题目要求

给一整数 n, 返回杨辉三角的前 n 行

输入 : n = 4
输出 :
[
 [1]
 [1,1]
 [1,2,1]
 [1,3,3,1]
]

解决方案(标准解决)

public class Solution {
    /**
     * @param n: a Integer
     * @return: the first n-line Yang Hui's triangle
     */
    public List<List<Integer>> calcYangHuisTriangle(int n) {
        List<List<Integer> > res = new ArrayList<>();
        int i, j;
        if (n == 0) {
            return res;
        }
        
        for (i = 0; i < n; ++i) {
            List<Integer> t = new ArrayList<Integer>();
            t.add(1);   
            for (j = 1; j < i; ++j) {
                t.add(res.get(i - 1).get(j - 1) + res.get(i - 1).get(j));    
            }
            
            if (i > 0) {
                t.add(1);
            }
            res.add(t);
        }
        return res;
    }
}

767 · 翻转数组(简单)

题目要求

原地翻转给出的数组 nums不可以开辟额外的数组空间!

输入 : nums = [1,2,5]
输出 : [5,2,1]

解决方案

同样是双指针思想来解决问题

public class Solution {
    /**
     * @param nums: a integer array
     * @return: nothing
     */
    public void reverseArray(int[] nums) {
        // write your code here
        // 如果是长度为0或1的数组,就没必要继续进行操作
        if (nums.length == 0 || nums.length == 1) {
            return;
        }
        // 设置两个指针
        int left = 0, right = nums.length - 1;
        // 对两个指针所在位置的值进行交换
        // left <= right: 这是因为要保证奇数个元素时依旧可以对所有元素进行操作
        while (left <= right) {
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            // 更新下一轮left和right的位置
            left += 1;
            right -= 1;
        }
    }
}

539 · 移动零(简单)

题目要求

给一个数组 nums 写一个函数将 0 移动到数组的最后面,非零元素保持原数组的顺序。必须在原数组上操作,最小化操作数。

输入: nums = [0, 1, 0, 3, 12],
输出: [1, 3, 12, 0, 0].

解决方案(我自己的)

类似于冒泡算法,将0“冒泡”到最后,但这个算法不是最优解!

public class Solution {
    /**
     * @param nums: an integer array
     * @return: nothing
     */
    public void moveZeroes(int[] nums) {
        // write your code here
        for (int i = 0; i < nums.length - 1; i++) {
            for (int j = i; j < nums.length - 1; j++) {
                if (nums[j] == 0) {
                    swap(nums, j, j + 1);
                }
            }
        }
    }

    private void swap(int[] arr, int indexA, int indexB) {
        int temp = arr[indexA];
        arr[indexA] = arr[indexB];
        arr[indexB] = temp;
    }
}

解决方案(排名第一

public class Solution {
    /**
     * @param nums an integer array
     * @return nothing, do this in-place
     */
    public void moveZeroes(int[] nums) {
        // Write your code here
        int left = 0, right = 0;
        while (right < nums.length) {
            if (nums[right] != 0) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;
                left++;
            }
            right++;
        }
    }
}

479 · 数组第二大数(简单)

题目要求

在数组中找到第二大的数。

输入:[1,3,2,4]
输出:3

解决方案(最简单但非最佳

public class Solution {
    /**
     * @param nums: An integer array
     * @return: The second max number in the array.
     */
    public int secondMax(int[] nums) {
        // write your code here
        Arrays.sort(nums);
        int targetIndex = nums.length - 2;
        return nums[targetIndex];
    }
}

235 · 分解质因数(简单)(需要复习)

题目要求

将一个整数分解为若干质因数之乘积。

输入:660
输出:[2, 2, 3, 5, 11]

解决方案

质因数:每个合数都可以写成几个质数(也可称为素数)相乘的形式 ,这几个质数就都叫做这个合数的质因数。

  • 从小到大遍历[2,upperLimit],若num能够被i整除则循环除以i直到不能被整除,每次除以i都向答案值数组增加一个i,因为是从小到大遍历,则必定只有质数能被取为因数

  • upperLimit一般设定为num2num^2,因为一个数大于其根号的质因数最多只有一个,那么遍历其根号内的数可以将时间复杂度减小至根号n,若遍历完prime后该数不为1,则其值为最后一个质因数

public class Solution {
    /**
     * @param num an integer
     * @return an integer array
     */
    public List<Integer> primeFactorization(int num) {
        List<Integer> factors = new ArrayList<Integer>();
        for (int i = 2; i * i <= num; i++) {
            while (num % i == 0) {
                num = num / i;
                factors.add(i);
            }
        }
        //若最后剩余数不为1,则为最后一个质因数
        if (num != 1) {
            factors.add(num);
        }   
        return factors;
    }
}

407 · 加一(简单)(有难度)

题目要求

给定一个非负数,表示一个数字数组,在该数的基础上+1,返回一个新的数组。

该数字按照数位高低进行排列,最高位的数在列表的最前面。

输入:[1,2,3]
输出:[1,2,4]

输入:[9,9,9]
输出:[1,0,0,0]

解决方案

public class Solution {
    /**
     * @param digits: a number represented as an array of digits
     * @return: the result
     */
    public int[] plusOne(int[] digits) {
        
        // 加一的“1”
        int extra = 1;
        // 对于数组从后向前取
        for (int i = digits.length - 1; i >= 0; i--) {
            // 每一位都要加一
            int sum = digits[i] + extra;
            // 这一位的值由(sum/10)的余数计算而来
            // if 1~9 -> 1~9 ; if 10 -> 0
            digits[i] = sum % 10;
            // 这里的sum/10决定了只有发生“进位”时(sum=10)才能进入下一次循环判断前一位数是否需要更新
            extra = sum / 10;
            // 如果不进位(extra为0,例如8/10=0),就直接跳出循环
            if (extra == 0) {
                break;
            }
        }
        // 接上面:如果没有进位发生,就直接结束程序
        if (extra == 0) {
            return digits;
        }
        // 如果原数组全都进位了(999->1000),新数组的长度则加一
        // 若全都进位,则上面的for-loop产生三个0,并且extra为1,不满足extra为0的情况,所以length + 1
        int[] result = new int[digits.length + 1];
        // 新数组的第一位填充1
        result[0] = 1;
        return result;
    }
}

220 · 冰雹猜想(简单)

题目要求

数学家们曾提出一个著名的猜想——冰雹猜想。 对于任意一个自然数N,如果N是偶数,就把它变成N / 2; 如果N是奇数,就把它变成 3 * N+1。 按照这个法则运算下去,最终必然得1。 试问,该数通过几轮变换,会变成1呢?

输入: 
4
输出: 
2
解释: 
第一轮:4/2=2
第二轮:2/2=1
答案为2

解决方案

这个题不难,判断一下奇数偶数,分别进行计算就可以了。当num=1的时候循环停止。计数器需要从0开始,因为需要进行完首轮奇偶判断才能定义为“一次”。

public class Solution {
    /**
     * @param num: an integer
     * @return: return an integer
     */
    public int getAnswer(int num) {
        int count = 0;

        while (num != 1) {
            if (num % 2 == 0) {
                num = num / 2;
            } else {
                num = 3 * num + 1;
            }
            
            count += 1;
        }

        return count;
    }
}

53 · 翻转字符串(简单)

题目要求

给定一个字符串,逐个翻转字符串中的每个单词。

s = "the sky is blue"
"blue is sky the"

解决方案

public class Solution {
    /*
     * @param s: A string
     * @return: A string
     */
    public String reverseWords(String s) {
        // write your code here
        if (s == "") {
            return s;
        }
        // 按照空格分隔,允许多次匹配空格(错误示范:.split(" "))
        String[] afterSplit = s.trim().split("\\s+");
        // 删除每个单词后的标点(如果有)
        for (String string : afterSplit) {
            string = string.replaceAll("([a-z]+)[?:!.,;]*", "$1");
        }
        // 双指针做前后交换,实现翻转
        int left = 0, right = afterSplit.length - 1;

        while (left <= right) {
            String temp = afterSplit[left];
            afterSplit[left] = afterSplit[right];
            afterSplit[right] = temp;

            left++;
            right--;
        }
        // 将反转后的array中的每个元素添加到builder
        StringBuilder builder = new StringBuilder();
        for (String str : afterSplit) {
            builder.append(str).append(" ");
        }
        // 删除最后一个空格并return
        return builder.toString().trim();
    }
}

50 · 数组剔除元素后的乘积题目要求(简单)

给定一个整数数组A。 定义B[i]=A[0]...A[i1]A[i+1]...A[n1]B[i]=A[0]...A[i1]A[i+1]...A[n1]B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]B[i]=A[0]∗...∗A[i−1]∗A[i+1]∗...∗A[n−1] 计算B的时候请不要使用除法。请输出B

A = [1,2,3]
Output = [6,3,2]
B[0] = A[1] * A[2] = 6; B[1] = A[0] * A[2] = 3; B[2] = A[0] * A[1] = 2

解决方案

暴力枚举,计算所有情况

public class Solution {
    /*
     * @param nums: Given an integers array A
     * @return: A long long array B and B[i]= A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1]
     */
    public List<Long> productExcludeItself(List<Integer> nums) {
        // 建立一个list保存答案
        List<Long> resultB = new ArrayList<>();

        // 一些特殊情况的判断
        // Case 1:无元素
        if (nums.size() == 0) {
            resultB.add(new Integer(1).longValue());
            return resultB;
        } 
        // case 2:只有一个元素(元素为0或其他)
        if (nums.size() == 1 & nums.get(0) != 0) {
            resultB.add(new Integer(nums.get(0)).longValue());
            return resultB;
        } else if (nums.size() == 1 & nums.get(0) == 0) {
            resultB.add(new Integer(1).longValue());  // 其实这里并不是特别理解为什么有且只有一个元素0要返回1
            return resultB;
        }
        // 暴力枚举:遍历数组里的所有数字,找到对于每个数字而言的所有情况
        for (int currentIndex = 0; currentIndex < nums.size(); currentIndex++) {
            long result = 1;  // 保存对于这个数字而言的答案
            // 求出除了当前数字所有数字的乘积
            for (int calIndex = 0; calIndex < nums.size(); calIndex++) {
                if (calIndex == currentIndex) continue;
                result = result * nums.get(calIndex);
            }
            // 加入到答案list
            resultB.add(result);
        }
        return resultB;
    }
}

46 · 主元素(简单)

题目要求

给定一个整型数组,找出主元素,它在数组中的出现次数大于数组元素个数的二分之一。

数组 = [1, 1, 1, 1, 2, 2, 2]
output = 1

解决方案一 (我自己 - 使用HashMap)

public class Solution {
    /*
     * @param nums: a list of integers
     * @return: find a  majority number
     */
    public int majorityNumber(List<Integer> nums) {
        // write your code here
        // <key,value>:key是唯一的,代表数字,value代表次数
        HashMap<Integer,Integer> map = new HashMap<>();
        for (int number : nums) {
            if (map.containsKey(number)) {
                // 如果出现过就更新value
                map.put(number, map.get(number) + 1);
            } else {
               map.put(number, 1); 
            }
        }
        // 找到最大的value
        int maxShowUp = Collections.max(map.values());
        // 保存最大value所在的index
        int maxIndex = 0;
        // 遍历values,找到index
        for (int values : map.values()) {
            if (values == maxShowUp) break;
            maxIndex += 1;
        }
        // 遍历keys,找到最大value对应的key
        int maxKey = 0;
        int count = 0;
        for (int key: map.keySet()) {
            if (count == maxIndex) {
                maxKey = key;
            }
            count++;
        }

        return maxKey;
    }
}

解决方案二 (使用排序 - 最简单)

可以排序的情况下,代码只需要两行

因为占1/2以上的数一定是主元素,数组中间那个数也一定是它

时间复杂度 O(nlogn)O(nlogn)空间复杂度O(1)O(1)

public class Solution {
    /*
     * @param nums: a list of integers
     * @return: find a  majority number
     */
    public int majorityNumber(List<Integer> nums) {
        Collections.sort(nums);
        return nums.get(nums.size()/2);
    }
}

解决方案三 (标准方案)

这相当于遍历数组中的所有元素,只要元素出现的次数够多,它的count在经历过众多加减之后依旧大于0

public class Solution {

    public int majorityNumber(List<Integer> nums) {
        
        int currentMajor = 0;
        int count = 0;
        
        for(Integer num : nums) {
            if(count == 0) {
                currentMajor = num;
            }
            
            if(num == currentMajor) {
                count++;
            } else {
                count--;
            }
        }
        
        return currentMajor;
    }
}

9 · Fizz Buzz 问题(简单)

题目要求

给定整数 n ,按照如下规则打印从 1n 的每个数:

  • 如果这个数被3整除,打印fizz

  • 如果这个数被5整除,打印buzz

  • 如果这个数能同时被35整除,打印fizz buzz

  • 如果这个数既不能被 3 整除也不能被 5 整除,打印数字本身

input = 15
[
  "1", "2", "fizz",
  "4", "buzz", "fizz",
  "7", "8", "fizz",
  "buzz", "11", "fizz",
  "13", "14", "fizz buzz"
]

解决方案

注意条件的判断顺序,例如:15一旦被判断为可以被3或被5整除,那么就不会被判断为可以同时被整除!

条件要由小到大写!

public class Solution {
    /**
     * @param n: An integer
     * @return: A list of strings.
     */
    public List<String> fizzBuzz(int n) {
        // write your code here
        List<String> result = new ArrayList<>();
        for (int element = 1; element <= n; element++) {
            if (element % 3 == 0 & element % 5 == 0) {
                result.add("fizz buzz");
            } else if (element % 3 == 0 || element % 5 == 0) {
                String input = element % 3 == 0 ? "fizz":"buzz";
                result.add(input);
            } else {
                result.add(String.valueOf(element));
            }
        }
        return result;
    }
}

最后更新于