剑指Offer刷题Day1

剑指Offer

Day 1

3. 数组中重复的数字

解题关键: 数组nums的长度为n,且里面的数字取值范围是[0, n-1]。

思路一

通过开辟一个新的数组array,array的index代表nums数组中的值,array的值代表nums数组中元素出现的次数。

复杂度: 时间复杂度:O(n),空间复杂度:O(n)

public int findRepeatNumber(int[] nums) {
  int[] array = new int[nums.length];
  int ans = -1;
  for(int i = 0; i < nums.length; i++) {
    array[nums[i]] += 1;
    if (array[nums[i]] > 1) {
      ans = nums[i];
    }
  }
  return ans;
}

思路二

通过交换,让每个数字出现在其应该出现的位置

复杂度: 时间复杂度:O(n),空间复杂度:O(1)

public int findRepeatNumber(int[] nums) {
  boolean flag = false;
  int ans = -1;
  for (int i = 0; i < nums.length; i++) {
    if (nums[i] == i) {
      continue;
    }
    while (nums[i] != i) {
      if (nums[i] == nums[nums[i]]) {
        ans = nums[i];
        flag = true;
        break;
      } else {
        int tmp = nums[i];
        nums[i] = nums[nums[i]];
        nums[tmp] = tmp;
      }
    }
    if (flag == true) {
      break;
    }
  }
  return ans;
}

4. 二维数组中的查找

二维数组的规律:每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。

思路一

利用规律进行查找元素:从右上角开始,假设要查找的数字是x。

  • 如果当前数字大于x,那么就向左查找;
  • 如果当前数字小于x,那么就向下查找;
  • 如果当前数字等于x,那么就查找完毕,返回true;
  • 如果越界了,那么查找完毕,返回false。

复杂度: 时间复杂度:O(n),空间复杂度:O(1)

public boolean findNumberIn2DArray(int[][] matrix, int target) {
  if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
    return false;
  }
  int width = matrix[0].length;
  int height = matrix.length;
  int row = 0;
  int col = width - 1;
  boolean ans = false;
  while (row < height && col >= 0) {
    if (matrix[row][col] == target) {
      ans = true;
      break;
    } else if (matrix[row][col] > target) {
      col--;
    } else if (matrix[row][col] < target) {
      row++;
    }
  }
  return ans;
}

5. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

思路一

使用 StringBuilder ,加额外的空间进行组装

复杂度: 时间复杂度:O(n),空间复杂度:O(n)

public String replaceSpace(String s) {
  StringBuilder sb = new StringBuilder();
  for (int i = 0; i < s.length(); i++) {
    if (s.charAt(i) == ' ') {
      sb.append("%20");
    } else {
      sb.append(s.charAt(i));
    }
  }
  return sb.toString();
}

思路二

使用char[]数组,该数组的长度设置为当前长度的3倍,确保即使当前字符串全部是空格,也可以放得下。

复杂度: 时间复杂度:O(n),空间复杂度:O(3n)

public String replaceSpace(String s) {
  char[] chars = new char[s.length() * 3];
  char[] ss = s.toCharArray();
  int index = 0;
  for (char c : ss) {
    if (c == ' ') {
      chars[index++] = '%';
      chars[index++] = '2';
      chars[index++] = '0';
    } else {
      chars[index++] = c;
    }
  }
  return new String(chars, 0, index);
}

Tips: 将字符数组转化成String的方式

String(byte[] bytes, int offset, int length);

Constructs a new String by decoding the specified subarray of bytes using the platform’s default charset.

6. 从尾到头打印链表

思路一:

不考虑时间复杂度或者其他因素,可以直接通过将链表压入栈,紧接着弹出,就可以打印链表。

Java中官方JDK不推荐使用Stack。但是就算法题来说,为了说明算法还是使用了Stack

public int[] reversePrint(ListNode head) {
  Stack<Integer> stack = new Stack();
  while (head != null) {
    stack.push(head.val);
    head = head.next;
  }
  int[] ans = new int[stack.size()];
  for (int i = 0; i < ans.length; i++) {
    ans[i] = stack.pop();
  }
  return ans;
}

思路二:

本题还可以采用递归实现

递归终止条件是:head.next == null;

递归的终止操作是将其加入到 ArrayList 中

ArrayList<Integer> list = new ArrayList<>();
public int[] reversePrint(ListNode head) {
  recur(head);
  int[] ans = new int[list.size()];
  for(int i = 0; i < ans.length; i++) {
    ans[i] = list.get(i);
  }
  return ans;
}
public void recur(ListNode head) {
  if (head == null) return;
  recur(head.next);
  list.add(head.val);
}

7. 重建二叉树

根据二叉树遍历的顺序,

前序遍历:按照 根节点-左子树-右子树 遍历

中序遍历:按照 左子树-根节点-右子树 遍历

思路:

递归终止条件:in_st > in_end 时,说明这个时候已经遍历完了,直接返回null。

构建 node 节点,确定当前递归的 nodeindex 即为 i

TreeNode node = new TreeNode(preorder[pre_st]);

int i = map.get(preorder[pre_st]);

递归遍历 node 的左子节点,递归遍历 node 的右子节点。

最后返回 node

复杂度: 时间复杂度:O(n),空间复杂度:O(n)

HashMap<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
  for (int i = 0; i < inorder.length; i++) {
    map.put(inorder[i], i);
  }
  return recur(preorder, 0, 0, inorder.length - 1);
}

public TreeNode recur(int[] preorder, int pre_st, int in_st, int in_end) {
  if (in_st > in_end) {
    return null;
  }
  TreeNode node = new TreeNode(preorder[pre_st]);
  int i = map.get(preorder[pre_st]);
  node.left = recur(preorder, pre_st + 1, in_st, i - 1);
  node.right = recur(preorder, pre_st + i - in_st + 1, i + 1, in_end);
  return node;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章