class Solution {
/*
* param a: The first integer
* param b: The second integer
* return: The sum of a and b
*/
public int aplusb(int a, int b) {
// 主要利用异或运算来完成
// 异或运算有一个别名叫做:不进位加法
// 那么a ^ b就是a和b相加之后,该进位的地方不进位的结果
// 然后下面考虑哪些地方要进位,自然是a和b里都是1的地方
// a & b就是a和b里都是1的那些位置,a & b << 1 就是进位
// 之后的结果。所以:a + b = (a ^ b) + (a & b << 1)
// 令a' = a ^ b, b' = (a & b) << 1
// 可以知道,这个过程是在模拟加法的运算过程,进位不可能
// 一直持续,所以b最终会变为0。因此重复做上述操作就可以
// 求得a + b的值。
while (b != 0) {
int _a = a ^ b;
int _b = (a & b) << 1;
a = _a;
b = _b;
}
return a;
}
};
https://blog.csdn.net/nwsuaf_uestc/article/details/78788932
点睛之笔:我们发现只有一个数是五的倍数的时候,阶乘的后边就是0,如果一个数可以分解成5*5或者5*10、5*15那么就会结尾添加两个0,也就是说一个数除以五如果大于5那么就会多添加一个0。
public class Solution {
/*
* @param n: An integer
* @return: An integer, denote the number of trailing zeros in n!
*/
public long trailingZeros(long n) {
// write your code here, try to do it without arithmetic operators.
long sum = 0;
int count = 0;
while(n >= 5){
n = n / 5;
sum = sum + n;
count++;
}
return sum;
}
}
结论如下:我们可以得到以下规律:
class Solution {
/*
* param k : As description.
* param n : As description.
* return: An integer denote the count of digit k in 1..n
*/
public int digitCounts(int k, int n) {
// write your code here
int cnt = 0;
for (int i = k; i <= n; i++) {
cnt += singleCount(i, k);
}
return cnt;
}
public int singleCount(int i, int k) {
if (i == 0 && k == 0)
return 1;
int cnt = 0;
while (i > 0) {
if (i % 10 == k) {
cnt++;
}
i = i / 10;
}
return cnt;
}
};
public class Kth {
/*
* @param k : description of k
* @param nums : array of nums
* @return: description of return
*/
public static int kthLargestElement(int k, int[] nums) {
if (nums == null || nums.length == 0 || k < 1 || k > nums.length){
return -1;
}
return partition(nums, 0, nums.length - 1, nums.length - k);
}
private static int partition(int[] nums, int start, int end, int k) {
if (start >= end) {
return nums[k];
}
int left = start, right = end;
int pivot = nums[(start + end) / 2];
while (left <= right) {
while (left <= right && nums[left] < pivot) {
left++;
}
while (left <= right && nums[right] > pivot) {
right--;
}
if (left <= right) {
swap(nums, left, right);
left++;
right--;
}
}
if (k <= right) {
return partition(nums, start, right, k);
}
if (k >= left) {
return partition(nums, left, end, k);
}
return nums[k];
}
private static void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public static void main(String[] args) {
int k = 1;
int[] nums = {5,3,7,2,1};
int res = kthLargestElement(k, nums);
System.out.println(res);
}
}
public class MergeArray {
public static void main(String[] args) {
int[] A = {1,2,3,4};
int[] B = {2,4,6,8,9,15,34};
int[] res = merge(A,B);
for (int re : res) {
System.out.print(re + ",");
}
}
public static int[] merge(int[] a, int[] b){
int i = 0, j = 0, index = 0;
int[] C = new int[a.length + b.length];
// 这里判断数组都没有完毕的情况
while (i < a.length && j < b.length){
// 循环赋值
if (a[i] < b[j]){
C[index++] = a[i++];
}else {
C[index++] = b[j++];
}
}
//当 a 数组长度没有完结时
while (i < a.length){
C[index++] = a[i++];
}
//当 b 数组长度没有完结时
while (j < b.length){
C[index++] = b[j++];
}
return C;
}
}
【分析1】首先明确序列化与反序列化二叉树。所谓的序列化二叉树就是按照树的某种遍历方式遍历二叉树,将每个结点的值以某种特殊符号(例如,)分隔保存到一个字符串中,如果结点为空,则使用另外一种特殊符号(例如#)表示。反序列化的意思就是根据序列化的字符串重构出该二叉树。这里需要特别说明一点的是,遍历到叶子结点后,还需要继续向下遍历,结点为空,则用特殊字符(例如#)表示。
【分析2】对于二叉树的遍历方式选择上,原则上前、中、后和层次遍历都是可以的。但是为了能够很容易的获取二叉树的根结点,因此我们可以选择前序遍历顺序,这样遍历出来的第一个元素就是二叉树的根结点对应的值。
【分析3】对于二叉树的序列化来说,现在就变成了一个前序遍历二叉树的过程。如果当前结点不为空,则将当前结点对应的值加入到字符串中;如果当前结点为空,则将特殊字符(例如,#)加入到字符串中。
【分析4】根据前序序列化的二叉树字符串,我们需要重构该二叉树。根据前序遍历的特点,我们在获取根结点后,首先应该一直向左构建左子树,直到遇到空结点。如果当前结点为空,则应该返回到它的父结点,然后构造它的父结点的右子树。以此类推,显然这也是一个递归进行的过程。
class Solution {
/**
* This method will be invoked first, you should design your own algorithm
* to serialize a binary tree which denote by a root node to a string which
* can be easily deserialized by your own "deserialize" method later.
*/
public String serialize(TreeNode root) {
if (root == null) {
return "{}";
}
// 初始化树
ArrayList queue = new ArrayList();
// 将根节点入队列
queue.add(root);
// 递归将树节点入队列
for (int i = 0; i < queue.size(); i++) {
TreeNode node = queue.get(i);
if (node == null) {
continue;
}
queue.add(node.left);
queue.add(node.right);
}
// 这一步删除操作有点蒙蔽
while (queue.get(queue.size() - 1) == null) {
queue.remove(queue.size() - 1);
}
// 将队列元素输出到字符串
StringBuilder sb = new StringBuilder();
sb.append("{");
sb.append(queue.get(0).val);
for (int i = 1; i < queue.size(); i++) {
if (queue.get(i) == null) {
sb.append(",#");
} else {
sb.append(",");
sb.append(queue.get(i).val);
}
}
sb.append("}");
return sb.toString();
}
/**
* This method will be invoked second, the argument data is what exactly
* you serialized at method "serialize", that means the data is not given by
* system, it's given by your own serialize method. So the format of data is
* designed by yourself, and deserialize it here as you serialize it in
* "serialize" method.
*/
public TreeNode deserialize(String data) {
if (data.equals("{}")) {
return null;
}
// 去除{}, 逗号分割数据节点
String[] vals = data.substring(1, data.length() - 1).split(",");
// 建立树链
ArrayList queue = new ArrayList();
// 根节点
TreeNode root = new TreeNode(Integer.parseInt(vals[0]));
queue.add(root);
// 开始遍历
int index = 0;
boolean isLeftChild = true;
for (int i = 1; i < vals.length; i++) {
// 不管空节点,前序遍历 入队列
if (!vals[i].equals("#")) {
TreeNode node = new TreeNode(Integer.parseInt(vals[i]));
if (isLeftChild) {
queue.get(index).left = node;
} else {
queue.get(index).right = node;
}
queue.add(node);
}
if (!isLeftChild) {
index++;
}
isLeftChild = !isLeftChild;
}
return root;
}
}
输入: str="abcdefg", offset = 3
输出: str = "efgabcd"
样例解释: 注意是原地旋转,即str旋转后为"efgabcd"
class Solution:
def rotateString(self, s, offset):
s1 = s[:-offset]
s2 = s[-offset:]
# 直接s = s2 + s1 这样是通不过的
temp = s2 + s1
for i in range(len(temp)):
s[i] = temp[i]
# class Solution:
# def rotateString(self, s, offset):
# # write you code here
# if len(s) > 0:
# offset = offset % len(s)
# temp = (s + s)[len(s) - offset : 2 * len(s) - offset]
# for i in range(len(temp)):
# s[i] = temp[i]
使用两个仅支持 pop
和 push
的栈就可以完成, stack
储存压入的数据, minStack
储存最小值.
push
直接把元素压入 stack, 对于 minStack, 如果它为空则直接压入, 反之压入当前元素与 minStack 栈顶的最小值pop
两个栈都弹出一个元素, 返回 stack 弹出的元素min
返回 minStack 的栈顶还可以令 minStack 为单调栈, 即
push
时只有元素更小的时候才放入这个栈, 而pop
时只有栈顶与stack栈顶相同时才弹出这样可以节约一定的空间, 但是实质上空间复杂度仍然是 O(n), 且多了一些判断, 并不一定更优
public class MinStack {
private Stack stack;
private Stack minStack;
public MinStack() {
stack = new Stack();
minStack = new Stack();
}
public void push(int number) {
stack.push(number);
if (minStack.isEmpty()) {
minStack.push(number);
} else {
minStack.push(Math.min(number, minStack.peek()));
}
}
public int pop() {
minStack.pop();
return stack.pop();
}
public int min() {
return minStack.peek();
}
}