做做tx六道面试算法题
- 1) 洗牌算法:对52张牌洗牌,要求尽量洗乱,而且原牌不能在原位置上重复
- 2) 现在有n个微信群,每个群里面有2到m个人,设计一个数据结构存储这些信息,要求该结构能快速找出每一个人所在的所有的群Id。
- 3) 数组a[N],存放了数字1至N-1,其中某个数字重复一次。写一个函数,找出被重复的数字。时间复杂度必须为O(N), 空间复杂度不能是O[N]。
- 4) 现在有一个微信群,里面有n个人,每个人的id用整数int标示,现在要求找出id是对称数字的人出来,如3, 121, 12321。 请实现改查找函数,不能把整数转为字符串来判断。
- 5) 给定一个字符串,如“1234”,请实现一个函数,把这个字符串转成10进制整型,不能用系统函数
- 6) 有一个二叉树,每个节点的值是一个整数。写一个函数,判断这棵树中是否存在从根到叶子节点的一个路径,这个路径上所有节点之和为某一个值。存在返回1, 否则返回0。
1) 洗牌算法:对52张牌洗牌,要求尽量洗乱,而且原牌不能在原位置上重复
洗牌算法是常见的随机问题:将1-52张扑克牌重新洗牌。
Fisher–Yates随机置乱算法也被称做高纳德置乱算法,通俗说就是生成一个有限集合的随机排列。Fisher-Yates随机置乱算法是无偏的,所以每个排列都是等可能的,当前使用的Fisher-Yates随机置乱算法是相当有效的,需要的时间正比于要随机置乱的数,不需要额为的存储空间开销。
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println(Arrays.toString(shuffle(new int[]{1,2,3,4,5})));
}
//这里区分一下java中的随机数random.nextInt()与c++中的rand()
//比如在10到99产生一个随机数
//random.randInt(90)+10 rand()%(90)+10
static int [] shuffle(int [] a){
int n = a.length;
Random random = new Random();
int temp = 0;
for(int i =a.length-1;i>=0;i--){
int x = random.nextInt(i+1);
temp = a[i];
a[i]=a[x];
a[x] = temp;
}
return a;
}
}
这个算法随机选取一个随机数,然后与数组最后的元素进行交换,然后缩小数组范围,一直循环,知道最后一个。
2) 现在有n个微信群,每个群里面有2到m个人,设计一个数据结构存储这些信息,要求该结构能快速找出每一个人所在的所有的群Id。
这道题使用并查集即可:
https://www.acwing.com/problem/content/838/ 跟这题基本一致
在这里给一个模板:
(1)朴素并查集:
int p[N]; //存储每个点的祖宗节点
// 返回x的祖宗节点
int find(int x)
{
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
// 初始化,假定节点编号是1~n
for (int i = 1; i <= n; i ++ ) p[i] = i;
// 合并a和b所在的两个集合:
p[find(a)] = find(b);
3) 数组a[N],存放了数字1至N-1,其中某个数字重复一次。写一个函数,找出被重复的数字。时间复杂度必须为O(N), 空间复杂度不能是O[N]。
这道题是剑指Offer的经典题型,这道题的时间复杂度要求o(N),一般我的思路就是先排序再遍历,计算a[i]与a[i+1]是否相等,相等就return。
这里给出两种解题思路:
一种就是上述:
class Solution {
public int duplicateInArray(int[] nums) {
if(nums==null||nums.length==1){
return -1;
}
Arrays.sort(nums);
for(int i = 0 ; i < nums.length-1; i++){
if(nums[i]==nums[i+1]){
return nums[i];
}
}
return -1;
}
}
第二种做法:
将当前位置的数值放到他的位置上去,比如{2,2,3,3,4},将nums[0]的数应该放到nums[2]上,即将该数组放到他在数组中和他角标相等的位置,每次都检查要交换的位置上的数值是否一样,如果一样,则重复,如果不一样,则交换。
时间复杂度分析:o(n)
public int duplicateInArray(int[] nums) {
int len = nums.length;
if(nums==null||len==0)
return -1;
for(int i = 0;i<len;i++){
while(nums[i]!=i){
if(nums[i]==nums[nums[i]])
return nums[i];
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
}
return -1;
}
4) 现在有一个微信群,里面有n个人,每个人的id用整数int标示,现在要求找出id是对称数字的人出来,如3, 121, 12321。 请实现改查找函数,不能把整数转为字符串来判断。
public boolean find(int n){
int res = 0;
while(n!=0)
{
i=n%10;
res=(res*10)+i;
n/=10;
}
if(m==res){
return true;
}
retrun false;
}
5) 给定一个字符串,如“1234”,请实现一个函数,把这个字符串转成10进制整型,不能用系统函数
系统函数的实现:
java.lang.Integer中有一个bai方法:valueOf(String s,int radix)
int res = Integer.valueOf(s,10);
上面这个不合题意,所以换一个。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(cal(s));
}
public static int cal(String s){
int res = 0;
for(int i = 0; i < s.length(); i++){
res += (s.charAt(s.length()-1-i)-'0')*Math.pow(10,i);
}
return res;
}
}
6) 有一个二叉树,每个节点的值是一个整数。写一个函数,判断这棵树中是否存在从根到叶子节点的一个路径,这个路径上所有节点之和为某一个值。存在返回1, 否则返回0。
力扣经典题:
我们必须先了解二叉树的遍历框架
说到二叉树的遍历框架,很多人的脑海里立马蹦出来的就是前序、中序和后序遍历。但是机械地记住前中后序遍历没有太大意义,我们首先要掌握的是二叉树的递归思想
递归有两大要点:
反复调用自身
终止条件
二叉树结构上进行递归,则这两大要点变为:
递归调用自己两个子树
在叶结点处终止递归
调用子树的部分是重点。我们需要保证在子树上求解的是与原问题相同的子问题,才能递归调用自身。而终止条件可以放在最后作为细节考虑。
boolean hasPathSum(TreeNode root, int sum){
if(root==null){
return false;
}
if(root.left==null&&root.right==null){
return root.value==sum;
}
int target=sum-root.value;
return hasPathSum(root.left, target)||hasPathSum(root.right, target);
}
okk !!! 希望对大家有所帮助!!!有问题评论区见
111