LeetCode练习与总结

(1)Two Sum

找出数组中两个数刚好等于target的位置。【难度:低级

法一:无脑遍历,时间复杂度O(n^2)

public int[] twoSum(int[] nums, int target) {
    int[] result = new int[2];
    int m = 0;
    int n = 0;
    for (int i = 0; i < nums.length; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[i] + nums[j] == target) {
                m = i;
                n = j;
                break;
            } else {
                continue;
            }
        }
    }
    result[0] = m;
    result[1] = n;
    return result;
}

法二:官网给出的参考答案,使用HashMap记录了元素位置,时间复杂度O(n)

public int[] twoSumSolution3(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement)) {
            return new int[] { map.get(complement), i };
        }
        map.put(nums[i], i);
    }
    throw new IllegalArgumentException("No two sum solution");
}

小结: 尽管使用两层遍历结构也可以找出最终答案,但其牺牲了太多的时间。而官网给出的参考,以值为键,以位置为值,存放起来在Hash列表中,判断是否存在是只需要找出互补值,使用containsKey()进行判断,只需要一次遍历就可以找到答案,缩短了寻找耗时。


(2)给出两个逆序链表,要求得其相加的结果。【难度:中级

// 输入输出如下:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
// 链表定义如下:
class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}

法一:做一个游标用以操作当前相关的数据

public static ListNode addTwoNumbers(ListNode l1, ListNode l2) {

    ListNode result = new ListNode(0);// result记录了最开始的指针起点,不方便放到循环中运算
    ListNode curr = result; // 要找一个做游标

    int carry = 0;

    while (l1 != null || l2 != null || carry != 0) { // 还有下个元素

        int x = (l1 != null) ? l1.val : 0;
        int y = (l2 != null) ? l2.val : 0;
        int sum = carry + x + y;

        carry = sum / 10;
        curr.val = sum % 10;

        l1 = (l1 != null) ? l1.next : null;
        l2 = (l2 != null) ? l2.next : null;

        if (l1 == null && l2 == null && carry == 0) {
            break;
        }

        curr.next = new ListNode(0);
        curr = curr.next;
    }

    return result;
}

官网示例:

public static ListNode addTwoNumbersSolution1(ListNode l1, ListNode l2) {
    ListNode dummyHead = new ListNode(0);
    ListNode p = l1, q = l2, curr = dummyHead;
    int carry = 0;
    while (p != null || q != null) {
        int x = (p != null) ? p.val : 0;
        int y = (q != null) ? q.val : 0;
        int sum = carry + x + y;
        carry = sum / 10;
        curr.next = new ListNode(sum % 10);
        curr = curr.next;
        if (p != null)
            p = p.next;
        if (q != null)
            q = q.next;
    }
    if (carry > 0) {
        curr.next = new ListNode(carry);
    }
    return dummyHead.next;
}

小结: 此题的难度在于如何使用列表将逆序链表作加,需要注意的是,此题在循环操作中需要使用另外一个ListNode进行遍历,操作完后,只要找到链表头结点作为返回即可。

(3)给定一字符串,输出不带重复字符的最长子串的长度。【难度:中级

输入输出示例如下:
"pwwkew", the answer is "wke"

参考示例:

public static int lengthOfLongestSubstringSolution2(String s) {
    int n = s.length(), ans = 0;
    Map<Character, Integer> map = new HashMap<>(); // current index of
                                                    // character
    // try to extend the range [i, j]
    for (int j = 0, i = 0; j < n; j++) {
        if (map.containsKey(s.charAt(j))) {
            i = Math.max(map.get(s.charAt(j)), i);
        }
        ans = Math.max(ans, j - i + 1);
        map.put(s.charAt(j), j + 1);
    }
    return ans;
}

小结: 示例代码非常的简洁,这里依然是借助了HashMap的记忆功能,(以值为键,以位置为值),使用中需要特别注意containsKey和put方法的使用。

(6)给定一字符串与数字n,要求将字符串转换为高度为n的锯齿后,以横向顺序输出新的字符串。

输入输出示例:
输入为:"PINALSIGYAHRPISKYTS"5
其锯齿模式如下:
第 【1】 行:     P    Y    Y
第 【2】 行:     I   GA   KT
第 【3】 行:     N  I H  S S
第 【4】 行:     A S  R I
第 【5】 行:     L    P
返回为:PYYIGAKTNIHSSASRILP

这道题就是单纯的寻找规律即可,在求解中笔者将其分为“上坡”和“下坡”两个过程进行分析,找出每个字符与他下一个字符步长。也有博客提出了其他更简单的规律,学习一下,可以参考【这里】

public static String convert(String s, int numRows) {

    String result = "";
    boolean isDown = true;// true表下坡,false表上坡
    boolean isCenter = false;

    if (numRows == 1) {
        return s;
    }

    for (int i = 0; i < numRows; i++) {

        int j = i;// 初始化j
        int lenth = 0;
        String line = "";

        if (i == 0) {
            isDown = true;
            isCenter = false;
        } else if (i == numRows - 1) {
            isDown = false;
            isCenter = false;
        } else {
            isDown = true;
            isCenter = true;
        }

        System.out.print("第 【" + (i + 1) + "】 行:\t ");

        while (j < s.length()) {
            Character ch = s.charAt(j);
            result = result + ch;

            if (isDown) {
                lenth = (numRows - (i + 1)) * 2;
            } else {
                lenth = i * 2;
            }

            line = line + ch;
            int num = 0;
            if (isCenter) {
                num = isDown ? lenth / 2 : lenth / 2 - 1;
            } else {
                num = lenth / 2;
            }

            j = j + lenth;
            if (j >= s.length())
                break;
            if (isCenter) {
                isDown = isDown ? false : true; // 运行一次则反向
            }
            for (int k = 0; k < num; k++) {
                line = line + " ";
            }
        }

        System.out.println(line);
    }

    return result;
}

(7)给定一数字,返回其逆序数字

Reverse digits of an integer.

Example1: x = 123, return 321
Example2: x = -123, return -321
    /**
     * 返回回环数字
     * 
     * @param x
     * @return
     */
    public static int reverse(int x) {

        final int max = 0x7fffffff; // int最大值
        final int min = 0x80000000; // int最小值

        boolean isPositive = (x >= 0) ? true : false;
        long result = 0;

        while (x != 0) {

            result = result * 10 + x % 10;

            if (result > max || result < min) // 溢出处理
            {
                result = isPositive ? max : min;
                return 0;
            }

            // 更新x
            x /= 10;
        }

        return (int) result;
    }

小结: 还是比较简单,但要注意对溢出情况的处理。

(8)将String型转为int型,尽可能考虑多种情况

    public static int myAtoi1(String str) {
        final int INT_MAX = 0x7fffffff;
        final int INT_MIN = 0x80000000;
        boolean isPositive = true;

        long result = 0;
        str = str.trim();

        for (int i = 0; i < str.length(); i++) {

            char ch = str.charAt(i);

            if (i == 0 && ch == '-') {
                isPositive = false;
                continue;
            }
            if (i == 0 && ch == '+') {
                continue;
            }
            if (i != 0 && (ch == '-' || ch == '+')) {
                break;
            }

            int temp = ch - '0';

            if ((temp > 10 || temp < 0) && ch != '-' && ch != '+') {
                break;
                // throw new IllegalArgumentException("出现了非法字符,无法进行转换!");
            }

            if (!isPositive)
                temp = -temp;

            result = (long) (result * 10 + temp);

            if (!isPositive && result > 0) {
                result = -result;
            }

            if (result > INT_MAX || result < INT_MIN) {
                result = (result > 0) ? INT_MAX : INT_MIN;
                break;
            }
        }

        return (int) result;
    }

(9)判断一个数字是否为回文数

    /**
     * 判断x是否为回文数字
     * 
     * @param x
     * @return
     */
    public static boolean isPalindrome(int x) {
        if (x < 0) {
            return false;
        }

        int cnt = 0;

        Map<Integer, Integer> map = new HashMap<Integer, Integer>();

        while (x != 0) {

            map.put(cnt, x % 10);

            cnt++;// 统计数字位数
            x /= 10;
        }

        for (int i = 0; i < cnt / 2; i++) {
            if (map.get(i) != map.get(cnt - i - 1)) {
                return false;
            }
        }

        return true;
    }

(19)删除链表倒数第N个节点

输入:
链表 = 1 --> 8 --> 3 --> 4,n=4
输出如下:
8 --> 3 --> 4
class ListNode {
    int val;
    ListNode next;

    ListNode(int x) {
        val = x;
    }
}
public static ListNode removeNthFromEnd(ListNode head, int n) {

    ListNode myList[] = new ListNode[100];

    ListNode dumyHead = new ListNode(0), p = dumyHead;
    p.next = head;

    int cnt = 0;
    while (p != null) {
        myList[cnt] = p;
        p = p.next;
        cnt++;
    }

    ListNode removeP = myList[cnt - n - 1]; // 找到需要删除的节点位置
    removeP.next = removeP.next.next; // 删除节点

    return dumyHead.next;
}

小结:新建一链表,将其next指向需求解的链表头部,遍历该链表,使用对象数组存储链表头部信息,遍历完成后通过数组信息进行节点删除操作。(ps:尽量使用原生态操作提升运行效率!)

(20)判断括号关闭顺序是否合法

主要判断三对括号的关闭顺序
The brackets must close in the correct order, "()" , "()[]{}" and "{[([])]}" are all valid but "(]" and "([)]" are not.

法一:采用递归进行求解

public static boolean isValid(String s) {
    int len = s.length();
    // 递归结束条件判断
    if (len == 0) {
        return true;
    } else if (len == 1) {
        return false;
    } else {
        while (len >= 2) {
            for (int i = 0; i < len - 1; i++) {
                // 括号匹配,则删掉递归
                if (isBracketClose(s.charAt(i), s.charAt(i + 1))) {
                    s = s.substring(0, i) + s.substring(i + 2);// 删除对括号递归
                    return isValid(s);
                }
            }
            if (len == s.length()) {
                return false;
            } else {
                len = s.length();
            }
        }
        return false;
    }
}

/**
 * 括号是否关闭
 * 
 * @param left
 * @param right
 * @return
 */
public static boolean isBracketClose(char left, char right) {
    if (left == '{' && right == '}') {
        return true;
    }
    if (left == '[' && right == ']') {
        return true;
    }
    if (left == '(' && right == ')') {
        return true;
    }
    return false;
}

法二:利用堆栈先进后出的特性进行求解

代码待实现

小结:递归求解,主要要找出递推方式,并考虑递归结束条件。在求解过程中,如果关闭顺序合法,字符串中必然有一对括号是存在的,就可删掉这对括号进行递归。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值