java算法题解答(一)

1、自己答案

    /**
     * @param A: An integer array
     * @return: An integer
     */
    public int singleNumber(int[] A) {
        Set<Integer> set = new HashSet<>();
        for (int i = 0;i<A.length ;i++ ){
            boolean flag = set.add(A[i]);
            if (!flag) {
                set.remove(A[i]);
            }
        }
        Iterator<Integer> iterator = set.iterator();
        return iterator.next();
    }  

解读:使用set集合保存数据,当返回false时表示已经保存过该数值,此时移除数值,最后集合里剩下的那个数值就是不重复的。
更优解

    public int singleNumber(int[] A) {
        if(A == null || A.length == 0) {
            return -1;
        }
        int res = 0;
        for (int i = 0; i < A.length; i++) {
            res ^= A[i];
        }
        return res;
    }

解读:异或运算,不同为1,相同为0,任意相同数字返回0(即0000 0000),只有一个单独的数字与0做异或运算,例0000 0101,相同返回0,不同返回1,即返回该数字本身,一次遍历获取结果,时间复杂度O(n)。
2、自己答案

     /**
     * @param numbers: An array of Integer
     * @param target: target = numbers[index1] + numbers[index2]
     * @return: [index1, index2] (index1 < index2)
     */
    public int[] twoSum(int[] numbers, int target) {
            // write your code here
            if (numbers == null || numbers.length == 0){
                return null;
            }
            int[] res = new int[2];
            Map<Integer,Integer> map = new HashMap<>();
            for (int i = 0; i < numbers.length; i++) {
                int number = numbers[i];
                map.put(i,number);
            }
            for(Integer index : map.keySet()){
                Integer numOne = map.get(index);
                for (Integer ind : map.keySet()) {
                    Integer numTwo = map.get(ind);
                    if (ind == index){
                        continue;
                    }
                    if (numOne + numTwo == target){
                        if (ind < index){
                            res[0] = ind;
                            res[1] = index;
                            return res;
                        }else {
                            res[0] = index;
                            res[1] = ind;
                            return res;
                        }
                    }
                }
            }
            return res;
        }

解读:遍历,使用map集合保存全部数据,key为索引,value为对应值,再对map集合进行遍历,找到和为指定值时即可返回。
更优解

    public int[] twoSum(int[] numbers, int target) {
            // write your code here
            if (numbers == null || numbers.length == 0){
                return null;
            }
            Map<Integer,Integer> map = new HashMap<>();
            for (int i = 0; i < numbers.length; i++) {
                int number = numbers[i];
                if (map.get(number) != null){   //说明之前存在某个数字与该数字和为目标数值
                    return new int[]{map.get(number),i};	//前一个数值的index必然小于当前数值的index
                }
                map.put(target-number,i);   //将目标数值与当前数字的差作为key,index作为value
            }
            int[] res = new int[]{};
            return res;
        }

解读:由于整数数组中可能会存在负数,因此不能在遍历时将小于目标数值的数字排除,所有数字都要保存。需要保存的有index及数字两个数值作为一组,使用map保存数据,key为目标数值与当前数字的差,value则为数字对应index。例:目标数值是15,当前数字是7,index为1,保存的map的key就是8,需要找到的数字即8,因此在遍历到8的时候就是找到了需要的答案,即7对应的index通过map获取,8的索引即为当前index,放入数组返回即可。时间复杂度为O(n)。
3、自己答案

public class Text {
    public static void main(String[] args) {
        String str = "asdgjhasbj";
        char[] chars = str.toCharArray();
        new Text().rotateString(chars,5);
    }
    /**
     * @param str: An array of char
     * @param offset: An integer
     * @return: nothing
     */
    public void rotateString(char[] str, int offset) {
        // write your code here
        if (str == null || str.length == 0){
            return;
        }
        offset = offset % str.length;
        if (offset == 0){
            return;
        }
        int index = str.length - (offset);
        int indexB = index;
        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < str.length; i++) {
            if (i < offset || i < indexB){
           		sbf.append(str[i]); //保存不需要翻转的全部字符
                if (i < offset){
                    str[i] = str[index];
                    index++;
                }
        	}else {
                break;
            }
        }
        for (int j = 0; j < sbf.length(); j++) {
            char c = sbf.toString().charAt(j);
            if (offset+j < str.length){
                str[offset+j] = c;
            }
        }
        System.out.println(Arrays.toString(str));
    }
}

解读:index表示被翻转的字符开始处所在索引,offset表示翻转字符长度,首先将需要翻转的字符进行翻转,放到对应位置,翻转指定长度offset的字符,由于index之前所有字符都要进行翻转,因此将index前的所有字符进行保存,例:str=“abcdefg”,offset为2,index为5,第一次翻转后变为fgcdefg,保存的字符串为abcde。再次遍历保存的字符串,将所有字符按顺序保存到数组中,数组索引从offset处开始,例fgcdefg,保存的字符串为abcde,offset为2,从c处开始保存对应的字符, 即c->a,d->b···最后字符串变为fgabcde。
其它解法:

    public void rotateString(char[] str, int offset) {
            // write your code here
            if (str == null || str.length == 0)
                return;
    
            offset = offset % str.length;
            reverse(str, 0, str.length - offset - 1);
            reverse(str, str.length - offset, str.length - 1);
            reverse(str, 0, str.length - 1);
            System.out.println(Arrays.toString(str));
    }
    
    private void reverse(char[] str, int start, int end) {
        for (int i = start, j = end; i < j; i++, j--) {
            char temp = str[i];
            str[i] = str[j];
            str[j] = temp;
        }
    }

解读:实现了一个从指定位置开始到指定位置结束的翻转方法,先将字符从开始到需要截取字符的开始的索引处进行翻转,再将后半部分进行翻转,最后将整个字符串进行翻转,例:str=“abcdefg”,offset为2,第一次翻转变为edcbafg,第二次翻转变为edcbagf,第三次翻转变为fgabcde。
4、自己答案

public class Text {
    public static void main(String[] args) {
        List<Integer> list = new Text ().getNarcissisticNumbers(7);
        System.out.println(list.toString());
    }
    /**
     * @param n: The number of digits
     * @return: All narcissistic numbers with n digits
     */
    public List<Integer> getNarcissisticNumbers(int n) {
        // write your code here
        List<Integer> list = new ArrayList<>();
        if (n <= 0){
            return new ArrayList<>();
        }
        int start ;
        int end ;
        if (n == 1){
            start = 0;
            end = 9;
        }else {
            start = new Double(Math.pow(10,n-1)).intValue();
            end = new Double(Math.pow(10,n)).intValue()-1;
        }
        for (int i = start; i <= end; i++) {
            int add = 0;
            int num = i;
            while (num != 0){	//n为0时说明所有位上的数字已经计算完
                add += Math.pow(num % 10,n);	//对每位上的数字进行n次方求和
                if (add > i){	//和已经大于当前数字,不需要继续计算,直接返回
                    break;
                }
                num = num / 10;
            }
            if (add == i){	//水仙花数
                list.add(i);
            }
        }
        return list;
    }
}

解读:首先根据输入的n找到需要判断的数值区间,Math.pow(x,y),此方法得到x的y次方,然后对每个数字进行各个位上的n次方的求和,如果是水仙花则保存返回。
其他解法:暂无。
5、自己答案
使用多个if

public static void main(String[] args) {
        List<String> list = new Text().fizzBuzz(35);
        System.out.println(list.toString());
    }
    /**
     * @param n: An integer
     * @return: A list of strings.
     */
    public List<String> fizzBuzz(int n) {
        List<String> list = new ArrayList<>();
        // write your code here
        for (int i = 1; i <= n; i++) {
            if (i % 15 == 0){	//既能被3整除又能被5整除
                list.add("fizz buzz");
            }else if (i % 3 == 0){	//被3整除
                list.add("fizz");
            }else if (i % 5 == 0){	//被5整除
                list.add("buzz");
            }else {
                list.add(i+"");
            }
        }
        return list;
    }

只使用一个if

	public List<String> fizzBuzz(int n) {
        List<String> list = new ArrayList<>();
        int i = 1;
        while (i <= n){
            while (i <= n && i % 3 != 0 && i % 5 != 0){	//既不能被3整除又不能被5整除
                list.add(i + "");
                i++;
            }
            if (i <= n && i % 3 == 0 && i % 5 == 0){	//既能被3整除又能被5整除
                i++;
                list.add("fizz buzz");
                continue;
            }
            while (i <= n && i % 3 == 0){	//被3整除
                i++;
                list.add("fizz");
            }
            while (i <= n && i % 5 == 0){	//被5整除
                i++;
                list.add("buzz");
            }
        }
        return list;
    }

解读:使用while来代替if判断,取巧。
6、答案

	public static void main(String[] args) {
        int sum = new Text().aplusb(4,71);
        System.out.println(sum);
    }
    /**
     * @param a: An integer
     * @param b: An integer
     * @return: The sum of a and b
     */
    public int aplusb(int a, int b) {
        if (b == 0){
            return a;
        }
        //1、各位相加 不进位 0+0 0 0+1 1 1+0 1 1+1 0 相同为0 不同为1 异或运算
        int numA = a^b;
        //2、进位 0+0 0+1 1+0 不进位 1+1 进位  相当于先做位与运算保留1+1的位  再做向左移位 0 0 0 1 << 00 00 00 10
        int numB = (a & b) << 1;
        //3、前两步得到的结果相加,调用自身方法
        return aplusb(numA,numB);
    }

解读:使用位运算符来计算。
计算加法时可以分三步,例如15+16
第一步,各位相加。10+10=20,5+6=11,如果不进位时,第一步结果是20+1=21
第二步,进位。10+10=20,不需要进位,5+6=11,需要进位,得到进位结果10
第三部,将前两步的和相加。21+10=31,得到结果
如果是需要再进位的,此时需要再次分三步一步步走,即运算不是一步计算到位,需要递归调用,例:89+98
1、80+90=170,9+8=17,70+7=77
2、80+90=170,进位,9+8=17,进位,得到100+10=110
3、77+110 即 1、100+0=100,70+10=80 7+0=7 得到187,2、无操作,3、得到结果为187
同理对于位运算也可以分三步:
第一步,各位相加,不进位。0+0=0,0+1=1,1+0=1,1+1=0,相当于相同位结果是0,不同则为1,即异或运算,因此第一步使用异或运算得到一个结果。
第二步,进位。0+0 0+1 1+0都不进位,1+1进位,相当于做位与运算得到结果再左移一位,即0+0=0 0+1=0 1+0=0 1+1=1 左移后变为00 00 00 10 即1+1进位,其余不进位。
第三步,前两步和相加,即递归调用自身即可。
7、自己答案

	public static void main(String[] args) {
        System.out.println(new Text().getSum(1,50));
    }
    /**
     * @param A: The A
     * @param B: The B
     * @return: Returns the sum of all qualified numbers
     */
    public int getSum(int A, int B) {
        // Write your code here
        if (A > B || A < 0 || B < 0){
            return 0;
        }
        int sum = 0;
        for (int i = A; i <= B; i++) {
            if (i % 3 == 0){
                sum += i;
            }
        }
        return sum;
    }

解读:遍历从A到B的所有数字,找到所有被3整除的数字加一起返回

	/**
     * @param A: The A
     * @param B: The B
     * @return: Returns the sum of all qualified numbers
     */
    public int getSum(int A, int B) {
        // Write your code here
        if (A > B || A < 0 || B < 0){
            return 0;
        }
        int sum = 0;
        if (A % 3==0){
            while (A <= B){
                sum += A;
                A += 3;
            }
        }else if (A % 3 == 1){
            A += 2;
            while (A <= B){
                sum += A;
                A += 3;
            }
        }else {
            A += 1;
            while (A <= B){
                sum += A;
                A += 3;
            }
        }
        return sum;
    }

解读:判断A是否被3整除,然后一直找到B,中间只取被3整除的数字相加,循环次数要少于上面方法。
8、自己答案

	public static void main(String[] args) {
        System.out.println(new Text().isUnique("asdgh"));
    }
    /*
     * @param str: A string
     * @return: a boolean
     */
    public boolean isUnique(String str) {
        // write your code here
        Set<String> set = new HashSet<>();
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            boolean flag = set.add(chars[i] + "");  //存在相同字符
            if (!flag){
                return false;
            }
        }
        return true;
    }

解读:使用set集合保存每个字符,利用其不可保存相同对象特性,当放入一个对象返回false时即找到了相同字符
其他答案

	 /*
     * @param str: A string
     * @return: a boolean
     */
    public boolean isUnique(String str) {
        // write your code here
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (str.indexOf(c) != str.lastIndexOf(c)){  //判断首个出现字符的索引和最后出现字符的索引是否相同,不同则重复
                return false;
            }
        }
        return true;
    }

解读:判断字符串中该字符出现的索引,如果只有一个该字符,则从前从后找到的索引应该一致,不一致时说明存在相同字符

	/*
     * @param str: A string
     * @return: a boolean
     */
    public boolean isUnique(String str) {
        // write your code here
        boolean[] arr = new boolean[256];
        for (int i = 0; i < str.length(); i++) {
            int c = str.charAt(i);
            if (arr[c]){    //存在相同字符
                return false;
            }
            arr[c] = true;  //将该字符对应数组值为true
        }
        return true;
    }

解读:因为ASCII字符只有256个,所以开辟一个256长度的数组,默认值全为false,遍历字符时判断数组该下标对应值是否为true,不为true将数组对应值改为true,表示出现过,为true说明说明已经出现过,此时重复出现
9、自己答案

	public static void main(String[] args) {
        System.out.println(new Text().reverseWords("hello world"));
        System.out.println(new Text().reverseWords("the sky is blue"));
        System.out.println(new Text().reverseWords("  the sky is blue "));
        System.out.println(new Text().reverseWords("the sky is blue "));
        System.out.println(new Text().reverseWords(" the sky is blue "));
        System.out.println(new Text().reverseWords(" the  sky   is blue "));
    }
    /*
     * @param s: A string
     * @return: A string
     */
    public String reverseWords(String s) {
        // write your code here
        String[] split = s.split(" );
        StringBuilder sbf = new StringBuilder();
        for (int i = split.length-1; i >= 0; i--) {
            if ("".equals(split[i])){
                continue;
            }
            sbf.append(split[i]).append(" ");
        }
        return sbf.toString();
    }

解读:按空字符串分割,如果是多个空字符串连在一起的,遍历数组时将空字符串时不要即可。
10、自己答案

	public static void main(String[] args) {
        System.out.println(new Text().firstUniqChar("abaccdeff"));
    }
    /**
     * @param str: str: the given string
     * @return: char: the first unique character in a given string
     */
    public char firstUniqChar(String str) {
        // Write your code here
        if (str == null || "".equals(str)){
            return ' ';
        }
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (str.indexOf(chars[i]) == str.lastIndexOf(chars[i])){
                return chars[i];
            }
        }
        return ' ';
    }

解读:挨个字符判断从头数和从后数的索引是否一致,不一致说明存在多个一样字符,一致说明唯一
11、自己答案

	public static void main(String[] args) {
        System.out.println(new Text().isLegalIdentifier("abaccdeff"));
        System.out.println(new Text().isLegalIdentifier(""));
        System.out.println(new Text().isLegalIdentifier("123_1das"));
        System.out.println(new Text().isLegalIdentifier("a123_"));
        System.out.println(new Text().isLegalIdentifier("_123"));
        System.out.println(new Text().isLegalIdentifier("a_123"));
    }
    /**
     * @param str: The identifier need to be judged.
     * @return: Return if str is a legal identifier.
     */
    public boolean isLegalIdentifier(String str) {
        // Write your code here.
        if (str == null || "".equals(str)){
            return true;
        }
        String regex = "[a-zA-Z_]+[0-9a-zA-Z_]*";
        if (str.matches(regex)){
            return true;
        }else {
            return false;
        }
    }

解读:使用正则表达式判断
12、自己答案

	public static void main(String[] args) {
        System.out.println(new Solution().deduplication(new int[]{2,5,8,2,4,1,6,5,2}));
        System.out.println(new Solution().deduplication(new int[]{1,3,1,4,4,2}));
    }
    /**
     * @param nums: an array of integers
     * @return: the number of unique integers
     */
    public int deduplication(int[] nums) {
        // write your code here
        int index = nums.length-1;
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i <= index; i++) {
            int numA = nums[i];
            boolean flag = set.add(numA);   //判断是否重复
            if (!flag){
                nums[i] = nums[index];
                nums[index--] = numA;
                i--;
            }
        }
        return index+1;
    }

解读:利用set集合保存元素唯一特性,重复元素向后放
13、自己答案

    class Interval {
        int start, end;
        public Interval(int start, int end) {
            this.start = start;
            this.end = end;
        }
    }
	public static void main(String[] args) {
        List<Interval> list = new ArrayList<>();
        Interval interval = new Interval(465,497);
        list.add(interval);
        interval = new Interval(386,462);
        list.add(interval);
        interval = new Interval(354,380);
        list.add(interval);
        interval = new Interval(134,189);
        list.add(interval);
        interval = new Interval(199,282);
        list.add(interval);
        interval = new Interval(18,104);
        list.add(interval);
        interval = new Interval(499,562);
        list.add(interval);
        interval = new Interval(4,14);
        list.add(interval);
        interval = new Interval(111,129);
        list.add(interval);
        interval = new Interval(292,345);
        list.add(interval);
        System.out.println(new Solution().canAttendMeetings(list));
    }
    /**
     * @param intervals: an array of meeting time intervals
     * @return: if a person could attend all meetings
     */
    public boolean canAttendMeetings(List<Interval> intervals) {
        // Write your code here
        for (int i = 0; i < intervals.size(); i++) {
            Interval intervalA = intervals.get(i);
            for (int j = i+1; j < intervals.size(); j++) {
                Interval intervalB = intervals.get(j);
                if (intervalA.start < intervalB.end && intervalA.end > intervalB.start){
                    return false;
                }
            }
        }
        return true;
    }

解读:逐个比较,时间交集条件是,一个的开始时间小于另一个的结束时间,并且结束时间大于另一个的开始时间
更优解:

	public boolean canAttendMeetings(List<Interval> intervals) {
        // Write your code here
        if(intervals == null || intervals.size() == 0) return true;
        Collections.sort(intervals, new Comparator<Interval>() {
            @Override
            public int compare(Interval o1, Interval o2) {
                return o1.start - o2.start;
            }
        });
        int end = intervals.get(0).end;
        for(int i = 1; i < intervals.size(); i++){
            if(intervals.get(i).start < end) {
                return false;
            }
            end = Math.max(end, intervals.get(i).end);
        }
        return true;
    }

解读:先对集合按照开始时间从小到大进行排序,然后遍历比较结束时间与开始时间,当某个时间段前的结束时间大于该时间段的开始时间,说明存在交集。
14.自己答案

	public static void main(String[] args) {
        System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},5));
        System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},2));
        System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},7));
        System.out.println(new Solution().searchInsert(new int[]{1,3,5,6},0));
    }
    /**
     * @param A: an integer sorted array
     * @param target: an integer to be inserted
     * @return: An integer
     */
    public int searchInsert(int[] A, int target) {
        // write your code here
        int index = 0;
        for (int i = 0; i < A.length; i++) {
            int num = A[i];
            int pre;
            if (num == target){
                index = i;
                break;
            }
            if (i != 0){
                pre = A[i - 1];
                if (pre < target){
                    if (num > target){
                        index = i;
                        break;
                    }else {
                        if (i == A.length - 1){
                            index = A.length;
                        }
                    }
                }
            }
        }
        return index;
    }

解读:遍历,找到对应目标数字,同时判断上一个数字和当前数字与目标数字比较,当上一个数字比目标数字小,当前数字比目标数字大时返回当前数字索引,当所有数字比目标数字小时返回数组长度,当所有数字比目标数字大时返回0
更优解

	public int searchInsert(int[] A, int target) {
        // write your code here
        if (A == null || A.length == 0){
            return 0;
        }
        int start = 0;
        int end = A.length - 1;
        while (start <= end){
            int mid = (start + end) / 2;
            if (A[mid] == target){
                return mid;
            }else if (A[mid] > target){
                end = mid - 1;
            }else {
                start = mid + 1;
            }
        }
        return end+1;
    }

解读:使用二分查找法,每次排除一半数据,找到目标数字时返回当前索引,未找到时返回后一个数字索引+1
15、自己答案

	/**
     * @param array: the input array
     * @return: the sorted array
     */
    public int[][] multiSort(int[][] array) {
        // Write your code here
        for (int i = 0; i < array.length; i++) {
            for (int j = i+1; j < array.length; j++) {
                if (array[i][1] < array[j][1]){
                    int[] tmp = array[j];
                    array[j] = array[i];
                    array[i] = tmp;
                }else if (array[i][1] == array[j][1] && array[i][0] > array[j][0]){
                    int[] tmp = array[j];
                    array[j] = array[i];
                    array[i] = tmp;
                }
            }
        }
        return array;
    }

解读:对数组排序两两比较排序,分值大的在前, 分值相同的学号小的在前
更优解:

	public int[][] multiSort1(int[][] array) {
        // Write your code here
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if (!cmp(array[i], array[j])) {
                    int tmp = array[i][0];
                    array[i][0] = array[j][0];
                    array[j][0] = tmp;

                    tmp = array[i][1];
                    array[i][1] = array[j][1];
                    array[j][1] = tmp;
                }
            }
        }

        return array;
    }

    boolean cmp(int[] a, int[] b) {
        if (a[1] > b[1]) {
            return true;
        }
        if (a[1] == b[1] && a[0] < b[0]) {
            return true;
        }
        return false;
    }

解读:两两比较,不交换地址,只交换数组里数据
16、冒泡排序

	/**
     * @param A: an integer array
     * @return: nothing
     */
    public void sortIntegers(int[] A) {
        // write your code here
        if (A==null || A.length == 0){
            return;
        }
        for (int i = 0; i < A.length; i++) {
            for (int j = i+1; j < A.length; j++) {
                if (A[i] > A[j]){
                    int temp = A[i];
                    A[i] = A[j];
                    A[j]= temp;
                }
            }
        }
    }

快速排序

	public void quickSort(int[] A,int start,int end){
        if (A==null || A.length == 0){
            return;
        }
        int temp = A[start];
        if (start >= end){
            return;
        }
        int index = end;
        for (int k = start; k <= index; k++) {
            if (A[k] >= temp) {
                int num = A[k];
                A[k] = A[index];
                A[index] = num;
                index--;
                if (A[k] != temp){
                    k--;
                }
            }
        }
        quickSort(A,start,index);
        quickSort(A,index+1,end);
    }

另一种快速排序

	public void quickSort1(int[] arr, int low, int high){
        if(arr.length <= 0) return;
        if(low >= high) return;
        int left = low;
        int right = high;

        int temp = arr[left];   //挖坑1:保存基准的值
        while (left < right){
            while(left < right && arr[right] >= temp){  //坑2:从后向前找到比基准小的元素,插入到基准位置坑1中
                right--;
            }
            arr[left] = arr[right];
            while(left < right && arr[left] <= temp){   //坑3:从前往后找到比基准大的元素,放到刚才挖的坑2中
                left++;
            }
            arr[right] = arr[left];
        }
        arr[left] = temp;   //基准值填补到坑3中,准备分治递归快排
        System.out.println("Sorting: " + Arrays.toString(arr));
        quickSort1(arr, low, left-1);
        quickSort1(arr, left+1, high);
    }

解读:冒泡排序:两两比较,较小的前移,复杂度O(n²)
快速排序:选择一个数作为基准,将比基准小的数放到基准数前,比基准大的放在后面,相等的放在哪边都行,然后分成两段再分别进行递归调用,复杂度O(nlogn)
17、答案

	/**
     * @param m: the limit
     * @param k: the sum of choose
     * @param arr: the array
     * @return: yes or no
     */
    public String depress(int m, int k, int[] arr) {
        // Write your code here.
        if (arr == null ||arr.length == 0){
            return "yes";
        }
        int[] res = new int[k];
        int index = 0;
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            if (index == k){
                Arrays.sort(res);
                if (arr[i] < res[index-1]){
                    sum = sum - res[index-1] + arr[i];
                    res[index-1] = arr[i];
                    if (sum < m){
                        return "yes";
                    }
                }
            }
            if (index < k){
                res[index] = arr[i];
                index++;
                sum += arr[i];
            }
        }
        return "no";
    }

解读:开辟一个k长的数组,作为最小堆,保存数组中遍历到的最小元素,发现这些数值的和小于目标数m,即返回yes,未找到则返回no

	public String depress(int m, int k, int[] arr) {
        // Write your code here.
        if (arr == null ||arr.length == 0){
            return "yes";
        }
        Arrays.sort(arr);
        int sum = 0;
        for (int i = 0; i < arr.length; i++) {
            if (i < k){
                sum += arr[i];
            }
        }
        if(sum < m){
            return "yes";
        }else {
            return "no";
        }
    }

解读:对整个数组进行排序,找到前k个数值和,与m进行判断
18、答案:

class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}
	
	/**
     * @param head: the given linked list
     * @return: the array that store the values in reverse order
     */
    public List<Integer> reverseStore(ListNode head) {
        // write your code here
        if (head == null){
            return null;
        }
        List<Integer> list = new ArrayList<>();
        while (head != null){
            list.add(head.val);
            head = head.next;
        }
        Collections.reverse(list);
        return list;
    }

其它解

	List<Integer> list = new ArrayList<>();
	public List<Integer> reverseStore(ListNode head) {
        // write your code here
        if (head == null){
            return null;
        }
        reverseStore(head.next);
        list.add(head.val);
        return list;
    }

解答:倒序放数据,想到递归方法,每次将下一个节点进行递归判断,存在则保存数值即可。
19、自己答案

    class ListNode {
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    /**
     * @param head: the head of linked list.
     * @return: a middle node of the linked list
     */
    public ListNode middleNode(ListNode head) {
        // write your code here
        if (head == null){
            return null;
        }
        if (head.next == null){
            return head;
        }
        List<ListNode> list = new ArrayList<>();
        int index = -1;
        while (head != null){
            list.add(head);
            head = head.next;
            index++;
        }
        return list.get(index/2);
    }

解读:遍历找到全部数据,取中间索引对应数据
20、自己答案

    class ListNode {
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    /**
     * @param head: The head of linked list.
     * @param val: An integer.
     * @return: The head of new linked list.
     */
    public ListNode insertNode(ListNode head, int val) {
        // write your code here
        ListNode listNode = new ListNode(val);
        ListNode res = head;
        if (head == null){
            return listNode;
        }else {
            while (head != null){
                ListNode cur = head;
                int curVal = head.val;
                    if (curVal > val){  //当前值大于给定值时,向前插入,只有头结点才有此情况
                    res = listNode;
                    listNode.next = head;
                    break;
                }else {
                    head = head.next;
                    if (head != null){  //下个节点不为null,进行当前值,下个结点值和给定值比较
                        int nextVal = head.val;
                        if (curVal <= val && nextVal >= val){
                            cur.next = listNode;
                            listNode.next = head;
                            break;
                        }
                    }else {     //下个节点值为null
                        cur.next = listNode;
                        break;
                    }
                }
            }
        }
        return res;
    }

解读:判断头节点值是否大于给定值,小于则改变头节点,大于则向下进行判断,当给定值大于最后一个节点值时,尾节点为给定值,介于两个节点之间时向中间插入替换
其他答案:

	public ListNode insertNode(ListNode head, int val) {
        // write your code here
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        ListNode p = dummy;

        while(p != null){
            ListNode next = p.next;

            if(next != null && next.val < val){
                p = p.next;
            }else{ //当p.val<val && next.val>val时代表找到插入节点的位置
                ListNode newNode = new ListNode(val);
                newNode.next = next;
                p.next = newNode;
                break;
            }
        }

        return dummy.next;
    }

21、自己答案

    class ListNode {
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    /**
     * @param head: the first node of linked list.
     * @return: An integer
     */
    public int countNodes(ListNode head) {
        // write your code here
        if (head == null){
            return 0;
        }
        int res = 0;
        while (head != null){
            head = head.next;
            res++;
        }
        return res;
    }

解读:遍历所有节点,找到节点数量
22、自己答案

    class ListNode {
        int val;
        ListNode next;
        ListNode(int x) {
            val = x;
            next = null;
        }
    }
    /**
     * @param head: The first node of linked list
     * @param n: the start index
     * @param m: the end node
     * @return: A ListNode
     */
    public ListNode deleteNode(ListNode head, int n, int m) {
        // Write your code here
        if (head == null || n > m){
            return null;
        }
        int index = 0;
        ListNode pre = null;
        ListNode res = head;
        while (head != null){
            if (n == 0){
                if (index == m){
                    return head.next;
                }
            }
            if (index == n-1){
                pre = head;
            }
            if (index == m){
                pre.next = head.next;
                return res;
            }
            head = head.next;
            index++;
        }
        return res;
    }

解答:判断n为0,则找到m处值即可直接返回,n不为0,使用中间变量保存n节点前的值,当找到第m个节点时修改中间变量的next节点,然后返回原头节点即可
23、答案

    class TreeNode {
        public int val;
        public TreeNode left, right;
        public TreeNode(int val) {
            this.val = val;
            this.left = this.right = null;
        }
    }
    /**
     * @param root: The root of binary tree.
     * @return: An integer
     */
    public int maxDepth(TreeNode root) {
        // write your code here
        if (root == null){
            return 0;
        }
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left, right) + 1;
    }

解读:从根节点分别向左右叶子节点找到最深处
24、答案

    class TreeNode {
        public int val;
        public TreeNode left, right;
        public TreeNode(int val) {
            this.val = val;
            this.left = this.right = null;
        }
    }
    /**
     * @param root: A Tree
     * @return: Inorder in ArrayList which contains node values.
     */
    public List<Integer> inorderTraversal(TreeNode root) {
        // write your code here
        Stack<TreeNode> stack = new Stack<TreeNode>();
        ArrayList<Integer> result = new ArrayList<Integer>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()){    
            while (cur != null){
                stack.push(cur);
                cur = cur.left;
            }
            cur = stack.pop();
            result.add(cur.val);
            cur = cur.right;
        }
        return result;
    }

解读:中序遍历:从根节点向下找子节点,从左找起,即最左的是第一个元素,然后从该节点向上找到其根节点,再找该根节点的右节点的最下的左节点,然后再依次向上找,最后返回遍历结果。
使用栈保存每一个根结点,当当前的节点的左节点不为空时,将当前节点入栈保存,当前节点指向左节点,直到当前节点为空,说明找到最左节点,将该值保存到集合中,然后从栈中获取根节点,当前节点指向根节点的右节点,存在则继续找该节点的左节点,不存在则以根节点作为该根的根节点的左节点进行循环遍历,直到找到所有节点为止。
25、答案

    class TreeNode {
        public int val;
        public TreeNode left, right;
        public TreeNode(int val) {
            this.val = val;
            this.left = this.right = null;
        }
    }
    /**
     * @param root: the root of the binary tree
     * @return: all root-to-leaf paths
     */
    public List<String> binaryTreePaths(TreeNode root) {
        // write your code here
        List<String> paths = new ArrayList<>();
        if (root == null) {
            return paths;
        }
        List<String> leftPaths = binaryTreePaths(root.left);
        List<String> rightPaths = binaryTreePaths(root.right);
        for (String path : leftPaths) {
            paths.add(root.val + "->" + path);
        }
        for (String path : rightPaths) {
            paths.add(root.val + "->" + path);
        }
        // root is a leaf
        if (paths.size() == 0) {
            paths.add("" + root.val);
        }
        return paths;
    }

解读:使用分治算法
26、答案

    class TreeNode {
        public int val;
        public TreeNode left, right;
        public TreeNode(int val) {
            this.val = val;
            this.left = this.right = null;
        }
    }
    /**
     * @param root: the root of the binary tree
     * @return: the number of nodes
     */
    public int getAns(TreeNode root) {
        // Write your code here
        if (root == null){
            return 0;
        }
        int left = getAns(root.left);
        int right = getAns(root.right);
        return left+right+1;
	}

解读:递归找到所有节点
27、答案

	/**
     * @param a: the n numbers
     * @param k: the number of integers you can choose
     * @return: how many ways that the sum of the k integers is a prime number
     */
    public int getWays(int[] a, int k) {
        // Write your code here
        if (a == null || a.length == 0 || k == 0){
            return 0;
        }
        return dfs(0, 0, k,a,0);
    }

    /**
     * 递归判断k个数为素数的总可能数
     * @param sum   综合
     * @param p 数组当前遍历到的索引
     * @param k  要求的k个数
     * @param a 数组
     * @param count 已经找到的素数个数
     * @return  总素数个数
     */
    public int dfs(int sum,int p,int k,int[] a,int count){
        if(k==0){
            if(isPrime(sum)){
                count += 1;
            }else {
                count += 0;
            }
        }else {
            for(int i=p;i<=a.length-k;i++){  //当前所选下标的最大值,若超过,则会选不够;因为这是按照从前往后的顺序以此进行选择
                count = dfs(sum+a[i],i+1,k-1,a,count);   //每递归一次,就会选出一个数来,k就减1
            }
        }
        return count;
    }

    /**
     * 判断是否为素数
     * @param num   数字
     * @return  素数返回true 否则返回false
     */
    public boolean isPrime(int num){
        if (num == 1){
            return false;
        }
        for (int i = 2; i < num; i++) {
            if (num % i == 0){
                return false;
            }
        }
        return true;
    }

解读:从第一个数开始找,第一个数不变,后面找到k-1个数进行组合,找完后再将第二个数作为基准进行查找,知道找遍所有的可能。
28、答案

	/**
     * @param nums: Give an array numbers of n integer
     * @return: Find all unique triplets in the array which gives the sum of zero.
     */
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> results = new ArrayList<>();

        if (nums == null || nums.length < 3) {
            return results;
        }

        Arrays.sort(nums);

        for (int i = 0; i < nums.length - 2; i++) {
            // skip duplicate triples with the same first numebr
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }

            int left = i + 1, right = nums.length - 1;
            int target = -nums[i];

            twoSum(nums, left, right, target, results);
        }

        return results;
    }

    public void twoSum(int[] nums,
                       int left,
                       int right,
                       int target,
                       List<List<Integer>> results) {
        while (left < right) {
            if (nums[left] + nums[right] == target) {
                ArrayList<Integer> triple = new ArrayList<>();
                triple.add(-target);
                triple.add(nums[left]);
                triple.add(nums[right]);
                results.add(triple);

                left++;
                right--;
                // skip duplicate pairs with the same left
                while (left < right && nums[left] == nums[left - 1]) {
                    left++;
                }
                // skip duplicate pairs with the same right
                while (left < right && nums[right] == nums[right + 1]) {
                    right--;
                }
            } else if (nums[left] + nums[right] < target) {
                left++;
            } else {
                right--;
            }
        }
    }

29、答案

    public class Node {
        int val;
        Node next;
        Node(int x) {
            val = x;
            next = null;
        }
    }
    /**
     * 遍历
     */
    public static Node reverseList(Node node){
        if (node == null){
            return null;
        }
        Node pre = null;   //保存上一个节点
        Node next = null;  //下一个节点
        while (node != null){     //a->b->c
            next = node.next;  //获取下一个节点     1、b  2、c
            node.next = pre;   //当前节点的下一个节点指向上一个节点,实现反转  1、a->null 2、b->a
            pre = node;       //上一个节点指向当前节点  1、a  2、b
            node = next;   //当前节点指向下一个节点  1、b  2、c
        }
        return pre;
    }

    /**
     * 递归
     */
    public static Node reverseList1(Node node) {
        if (node == null || node.next == null){
            return node;
        }
        Node temp = node.next; //下一个节点
        Node next = reverseList1(temp);    //从后向前获取节点
        temp.next = node;  //下一个节点的下一个节点指向当前节点  即 a->b  变为 b->a->b   head为a,即当前节点  temp为b节点 要反转,所以b节点的下一个节点指向a节点
        node.next = null; //断开当前节点对下个节点的引用  即 b->a->b  变为b->a
        return next;
    }

30、答案

	public static Node searchNode(Node head){
        if (head == null){
            return null;
        }
        Node pHead = head;  //一次走一步
        Node nHead = head;  //一次走两步
        while (nHead != null && nHead.next != null && nHead.next.next != null){ //后面够走两步
            nHead = nHead.next.next;
            pHead = pHead.next;
        }
        return pHead;   //奇数则返回正中间结点,偶数则返回中间两个结点中前一个结点
    }

解读:两个指针一起走,一个一次走两个结点,一个一次走一个结点,当走的快的指针到达尾部时,慢的指针刚好到达中间,偶数个结点时返回中间两个结点中前一个结点
31、答案

	public static boolean IsLoop(Node head){
        if (head == null){
            return false;
        }
        Node pHead = head;  //一次走一步
        Node nHead = head;  //一次走两步
        while (nHead != null && nHead.next != null){
            pHead = pHead.next;
            nHead = nHead.next.next;
            if (pHead == nHead){
                return true;
            }
        }
        return false;
    }

解读:一个快指针一次走两步,一个满指针一次走一步,若存在环,则两个指针一定会相遇,如果不存在环,快指针会先到达尾部指向null,每次循环时两个指针进行比较,直到相等(存在环)或者快指针指向null(不存在环)
32、答案

	public static Node deleteElem(Node head,int k){
        if (head == null || k < 1){
            return null;
        }
        Node pHead = head;  //一次走一步
        Node nHead = head;  //先走k步
        Node pre = null;    //保存上一个结点
        for (int i = 1; i < k && nHead != null; i++) {
            nHead = nHead.next;
            if (nHead == null){
                System.out.println("k不合法");
                return null;
            }
        }
        while (nHead.next != null){
            nHead = nHead.next;
            pre = pHead;
            pHead = pHead.next;
        }
        if (pre == null){
            head = head.next;
        }else {
            pre.next = pHead.next;
        }
        return head;
    }

解读:一个指针先走k步,然后两个指针一起走,直到先走的指针走到最后,走的慢的指针当前结点就是倒数第k个结点,一个指针保存当前结点的上一个结点,如果被删除的结点刚好是头结点, 则将头结点的下一个结点作为新的头结点,否则进行结点删除
33、答案

	public static Node mergeTwoLists(Node head,Node head1){
        if (head == null || head1 == null){
            return head == null ? head1 : head;
        }
        Node node = null;    
        Node res = null;    //返回结果头结点
        Node p = head;
        Node q = head1;
        while (p != null || q != null){
            if (p != null && q != null){
                if (p.val <= q.val){
                    if (node == null){
                        node = p;
                        res = node;
                    }else {
                        node.next = p;
                        node = node.next;
                    }
                    p = p.next;
                }else {
                    if (node == null){
                        node = q;
                        res = node;
                    }else {
                        node.next = q;
                        node = node.next;
                    }
                    q = q.next;
                }
            }else {
                if (p == null && q != null){
                    node.next = q;
                    q = q.next;
                }
                if (q == null && p != null){
                    node.next = p;
                    p = p.next;
                }
            }
        }
        return res;
    }

解读:同时遍历两个链表,将新链表指向值小的那个结点
其它答案:

	public static Node mergeTwoLists(Node node1, Node node2) {
        if(node1==null) return node2;
        if(node2==null) return node1;

        Node temp;
        if(node1.val<node2.val){
            temp = node1;
            temp.next = mergeTwoLists(node1.next,node2);
        }else{
            temp = node2;
            temp.next = mergeTwoLists(node1,node2.next);
        }
        return temp;
    }

解读:递归实现

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值