从0开始刷剑指Offer

剑指Offer题解

剑指 Offer 11. 旋转数组的最小数字

思路: 二分O(logn)

class Solution {
    public int stockManagement(int[] stock) {
        int l = 0;
        int r = stock.length - 1;
        while(l < r && stock[0] == stock[r]) r --;
        if(stock[r] >= stock[l]) return stock[0];
        while(l < r) {
            int mid = l + r >> 1;
            if(stock[mid] < stock[0]) r = mid;
            else l = mid + 1;
        }
        return stock[l];
    }
}

剑指 Offer 12. 矩阵中的路径

思路: 回溯O(n23k)

class Solution {
    int[] dx = new int[] {-1, 0, 1, 0};
    int[] dy = new int[] {0, 1, 0, -1};
    public boolean wordPuzzle(char[][] grid, String target) {
        char[] words = target.toCharArray();
        for(int i = 0; i < grid.length; i ++) {
            for(int j = 0; j < grid[i].length; j ++) {
                if(dfs(grid, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] grid, char[] target, int i, int j, int k) {
        if(i >= grid.length || i < 0 || j >= grid[0].length || j < 0 || grid[i][j] != target[k]) {
            return false;
        }
        if(k == target.length - 1) return true;
        grid[i][j] = '.';
        for(int num = 0; num < 4; num ++) {
            int a = i + dx[num];
            int b = j + dy[num]; 
            if(dfs(grid, target, a, b, k + 1)) return true;
        }
        grid[i][j] = target[k];
        return false;
    }
}

剑指 Offer 13. 机器人的运动范围

思路一: 宽搜O(nm)

class Solution {
    int[] dx = new int[]{-1, 0, 1, 0};
    int[] dy = new int[]{0, 1, 0, -1};
    public int wardrobeFinishing(int m, int n, int k) {
        if(m == 0 || n == 0) return 0;
        Queue<int[]> q = new LinkedList<>();
        boolean[][] visited = new boolean[m][n];
        q.add(new int[]{0, 0});
        int cnt = 0;
        while(!q.isEmpty()) {
            int[] t = q.poll();
            int x = t[0];
            int y = t[1];
            if(visited[x][y] || getSum(x, y) > k) continue;
            cnt ++;
            visited[x][y] = true;
            for(int i = 0; i < 4; i ++) {
                int a = x + dx[i];
                int b = y + dy[i];
                if(a >= 0 && a < m && b >= 0 && b < n) {
                    q.add(new int[]{a, b});
                }
            }
        }
        return cnt;
    }
    
    int getSum(int x, int y) {
        int s = 0;
        while(x != 0) {
            s += x % 10;
            x = x / 10;
        }
        while(y != 0) {
            s += y % 10;
            y = y / 10;
        }
        return s;
    }
}

思路二: 深搜O(nm)

class Solution {
    int m, n, cnt;
    boolean[][] visited;
    public int wardrobeFinishing(int m, int n, int cnt) {
        this.m = m;
        this.n = n;
        this.cnt = cnt;
        this.visited = new boolean[m][n];
        return dfs(0, 0, 0, 0);
    }
    public int dfs(int i, int j, int si, int sj) {
        if(i >= m || j >= n || cnt < si + sj || visited[i][j]) return 0;
        visited[i][j] =true;
        return 1 + dfs(i + 1, j, (i + 1) % 10 != 0 ? si + 1 : si - 8, sj) + dfs(i, j + 1, si, (j + 1) % 10 != 0 ? sj + 1 : sj - 8);
    }
}

剑指 Offer 14- I. 剪绳子

思路: 贪心O(n)

class Solution {
    public int cuttingBamboo(int n) {
        if(n <= 3) return n - 1;
        int res = 1;
        if(n % 3 == 1) {
            res = 4;
            n -= 4;
        }else if(n % 3 == 2) {
            res = 2;
            n -= 2;
        }
        while(n > 0) {
            res = (res * 3) % 1000000007;
            n -= 3;
        }
        return res;
    }
}

剑指 Offer 14- II. 剪绳子 II

思路: 贪心O(n) 同上

class Solution {
    public int cuttingBamboo(int n) {
        if(n < 4) return n - 1;
        long res = 1;
        if(n % 3 == 1) {
            res = 4;
            n -= 4;
        }else if(n % 3 == 2) {
            res = 2;
            n -= 2;
        }
        while(n > 0) {
            res = (res * 3) % 1000000007; //循环求余
            n -= 3;
        }
        return (int)res;
    }
}

剑指 Offer 15. 二进制中1的个数

思路一: 逐位判断O(logn)

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res += n & 1;
            n >>>= 1; //无符号右移
        }
        return res;
    }
}

思路二: 末位置0法O(logn)

public class Solution {
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res++;
            n &= n - 1;
        }
        return res;
    }
}

思路三: 末位移除法O(logn)

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
           n -= n & -n;
           res ++;
        }
        return res;
    }
}

剑指 Offer 16. 数值的整数次方

思路一:暴力O(n) 超出时间限制

class Solution {
    public double myPow(double x, int n) {
        if(n == 0) return 1.0;
        long N = n;
        return N >= 0 ? Mul(x, N) * 1.0 : 1.0 / Mul(x, -N);
    }
    public double Mul(double x, long b) {
        double temp = x;
        while(b -- > 1) {
            x *= temp;
        }
        return x;
    }
}

思路二:快速幂O(logn)

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        return N >= 0 ? quickMul(x, N) * 1.0 : 1.0 / quickMul(x, -N);
    }
    public double quickMul(double x, long b) {
        double res = 1;
        while (b > 0) {
            if((b & 1) > 0) {
                res *= x;
            } 
            b >>= 1;
            x *= x;
        }
        return res;
    }
}

剑指 Offer 17. 打印从1到最大的n位数

思路一:模拟O(n)

class Solution {
    public int[] countNumbers(int cnt) {
        int end = (int)Math.pow(10, cnt) - 1;
        int[] res = new int[end];
        for(int i = 0; i < end; i ++) {
            res[i] = i + 1;
        }
        return res;
    }
}

思路二:递归全排列O(10cnt)

class Solution {
        int[] res;
        int nine = 0; int count = 0; int start; int cnt;
        char[] num, loop = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    public int[] countNumbers(int cnt) {
            this.cnt = cnt;
            res = new int[(int)Math.pow(10, cnt) - 1];
            num = new char[cnt];
            start = cnt - 1;
            dfs(0);
            return res;
        }
        void dfs(int x) {
            // 
            if (x == cnt) { //x是指的是num数组的位数
                String s = String.valueOf(num).substring(start);
                if(!s.equals("0")) res[count ++] = Integer.parseInt(s);
                if(cnt - start == nine) start --;
                 //刚开始,cnt - start = 1, 当个位等于9时,nine = 1, start --;
                return;
                //因为这一步返回了,所以dfs继续下去,nine --;
            }
            for(char i : loop) {
                if(i == '9') nine ++;
                num[x] = i;
                dfs(x + 1);
            }
            nine --;
        }
}

剑指 Offer 18. 删除链表的节点

思路: (链表, 遍历) O(n)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        ListNode dummy = head;
        if(dummy.val == val) dummy = dummy.next;
        while (head != null && head.next != null) {
            if(head.next.val == val) {
                head.next = head.next.next;
            }
            head = head.next;
        } 
        return dummy;
    }
}

剑指 Offer 19. 正则表达式匹配

思路: 动态规划O(nm)

class Solution {
    public boolean articleMatch(String s, String p) {
        int m = s.length() + 1, n = p.length() + 1;
        boolean[][] dp = new boolean[m][n];
        dp[0][0] = true;
        for(int j = 2; j < n; j += 2)
            dp[0][j] = dp[0][j - 2] && p.charAt(j - 1) == '*';//第一行初始化为0,因为s初始化是0
        for(int i = 1; i < m; i++) {
            for(int j = 1; j < n; j++) {
                dp[i][j] = p.charAt(j - 1) == '*' ?
                    dp[i][j - 2] || dp[i - 1][j] && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.') :
                    dp[i - 1][j - 1] && (p.charAt(j - 1) == '.' || s.charAt(i - 1) == p.charAt(j - 1));
            }
        }
        return dp[m - 1][n - 1];
    }
}

剑指 Offer 20. 表示数值的字符串

**思路: (模拟,字符串处理)O(n) **

class Solution {
    public boolean validNumber(String s) {
          if(s.length() <= 0 || s == null ) {
            return false;
        }
       char[] res = s.trim().toCharArray();
       int len = res.length;
       boolean isNumber = false;
       boolean isE = false;
       boolean isDot = false;
       for(int i = 0; i < len; i ++ ){
           if(res[i] >= '0' && res[i] <= '9') {
               isNumber = true;
           }
         else  if(res[i] == '.') {
               if(isDot == true || isE == true) {
                   return false;
               }
               isDot = true;
           }
          else if(res[i] == 'e' || res[i] == 'E') {
               if(isE == true || !isNumber ) {
                   return false;
               }
               isE = true;
               isNumber = false;
           }
         else  if(res[i] == '-' || res[i] == '+') {
                if(i!=0 && res[i-1] != 'e' && res[i-1] != 'E'){
                    return false;
           }
           }
         else  return false;
       }
       return isNumber;
    }
}
  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值